@saptools/cf-hana 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/backup.ts","../src/config.ts","../src/errors.ts","../src/lob.ts","../src/format.ts","../src/003-backup-sql-parser.ts","../src/statements.ts","../src/001-backup-planner.ts","../src/builder.ts","../src/catalog.ts","../src/cf.ts","../src/credentials.ts","../src/driver/fake.ts","../src/driver/hdb.ts","../src/driver/index.ts","../src/history.ts","../src/safety.ts","../src/connection.ts","../src/pool.ts","../src/transaction.ts","../src/client.ts","../src/api.ts"],"sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { WriteBackupOperation, WriteBackupPlan } from \"./001-backup-planner.js\";\nimport { MAX_RESULT_STORE_BYTES } from \"./config.js\";\nimport { BackupRequiredError } from \"./errors.js\";\nimport { formatCsv } from \"./format.js\";\nimport type { QueryResult } from \"./types.js\";\n\nexport { buildWriteBackupPlan } from \"./001-backup-planner.js\";\nexport type { WriteBackupOperation, WriteBackupPlan };\n\nconst SAPTOOLS_DIR_NAME = \".saptools\";\nconst CF_HANA_DIR_NAME = \"cf-hana\";\nconst BACKUPS_DIR_NAME = \"backups\";\n\nexport interface SqlBackupWriteInput {\n readonly operation: WriteBackupOperation;\n readonly statementSql: string;\n readonly result: QueryResult;\n readonly selector?: string;\n}\n\nexport interface SqlBackupWriteOptions {\n readonly now?: Date;\n readonly saptoolsRoot?: string;\n readonly maxBytes?: number;\n}\n\nexport interface SqlBackupRecord {\n readonly directory: string;\n readonly statementPath: string;\n readonly backupPath: string;\n readonly metadataPath: string;\n readonly rowCount: number;\n}\n\nfunction defaultSaptoolsRoot(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nfunction backupTimestamp(now: Date): string {\n return now.toISOString().replace(/:/g, \"\").replace(\".\", \"\");\n}\n\nfunction backupMonth(now: Date): string {\n const year = String(now.getUTCFullYear());\n const month = String(now.getUTCMonth() + 1).padStart(2, \"0\");\n return `${year}${month}`;\n}\n\nfunction sanitizePathPart(value: string | undefined): string {\n const trimmed = value?.trim() ?? \"\";\n const normalized = trimmed\n .replace(/[^A-Za-z0-9._-]+/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n return normalized.length > 0 ? normalized : \"unknown-target\";\n}\n\nfunction backupBaseName(input: SqlBackupWriteInput, now: Date): string {\n return [sanitizePathPart(input.selector), input.operation, backupTimestamp(now)].join(\"-\");\n}\n\nexport function cfHanaBackupRoot(saptoolsRoot?: string): string {\n return join(saptoolsRoot ?? defaultSaptoolsRoot(), CF_HANA_DIR_NAME, BACKUPS_DIR_NAME);\n}\n\nexport async function writeSqlBackup(\n input: SqlBackupWriteInput,\n options: SqlBackupWriteOptions = {},\n): Promise<SqlBackupRecord> {\n const now = options.now ?? new Date();\n const directory = join(cfHanaBackupRoot(options.saptoolsRoot), backupMonth(now));\n const baseName = backupBaseName(input, now);\n const statementPath = join(directory, `${baseName}.statement.sql`);\n const backupPath = join(directory, `${baseName}.sql`);\n const metadataPath = join(directory, `${baseName}.json`);\n const metadata = {\n selector: input.selector ?? null,\n operation: input.operation,\n statementPath,\n backupPath,\n rowCount: input.result.rowCount,\n createdAt: now.toISOString(),\n };\n const csv = formatCsv(input.result);\n if (Buffer.byteLength(csv) > (options.maxBytes ?? MAX_RESULT_STORE_BYTES)) {\n throw new BackupRequiredError(\n \"Write backup exceeds the storage limit; the write was refused\",\n );\n }\n\n await mkdir(directory, { recursive: true, mode: 0o700 });\n await Promise.all([\n writeFile(statementPath, `${input.statementSql}\\n`, { encoding: \"utf8\", mode: 0o600 }),\n writeFile(backupPath, csv, { encoding: \"utf8\", mode: 0o600 }),\n writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n }),\n ]);\n\n return {\n directory,\n statementPath,\n backupPath,\n metadataPath,\n rowCount: input.result.rowCount,\n };\n}\n","export const CLI_NAME = \"cf-hana\";\nexport const CLI_VERSION = \"0.4.0\";\nexport const ENV_PREFIX = \"CF_HANA\";\n\nexport const DEFAULT_QUERY_TIMEOUT_MS = 60_000;\nexport const DEFAULT_CONNECT_TIMEOUT_MS = 60_000;\nexport const DEFAULT_POOL_MAX = 4;\nexport const DEFAULT_POOL_IDLE_MS = 60_000;\nexport const DEFAULT_AUTO_LIMIT = 100;\nexport const DEFAULT_CELL_LIMIT = 128;\nexport const MAX_CELL_LIMIT = 10_000;\nexport const DEFAULT_RESULT_TTL_MINUTES = 10_080;\nexport const DEFAULT_RESULT_SEARCH_LIMIT = 20;\nconst DEFAULT_MAX_RESULT_STORE_BYTES = 256 * 1024 * 1024;\nexport const MAX_RESULT_STORE_BYTES = resolveMaxResultStoreBytes();\nexport const HANA_CLOUD_DEFAULT_PORT = 443;\n\nfunction resolveMaxResultStoreBytes(): number {\n // The fake driver can lower the cap so E2E tests exercise refusal without\n // allocating hundreds of MiB. Real HANA connections always use the hard cap.\n if (readEnv(envName(\"DRIVER\")) !== \"fake\") {\n return DEFAULT_MAX_RESULT_STORE_BYTES;\n }\n const raw = readEnv(envName(\"FAKE_MAX_STORE_BYTES\"));\n const parsed = raw === undefined ? Number.NaN : Number(raw);\n return Number.isSafeInteger(parsed) && parsed > 0\n ? parsed\n : DEFAULT_MAX_RESULT_STORE_BYTES;\n}\n\n/** Build a `CF_HANA_*` environment variable name from a suffix. */\nexport function envName(suffix: string): string {\n return `${ENV_PREFIX}_${suffix}`;\n}\n\n/** Read an environment variable, treating blank values as absent. */\nexport function readEnv(name: string): string | undefined {\n const value = process.env[name];\n if (value === undefined) {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length === 0 ? undefined : trimmed;\n}\n\nexport interface SapCredentials {\n readonly email: string;\n readonly password: string;\n}\n\nexport interface SapCredentialOverrides {\n readonly email?: string | undefined;\n readonly password?: string | undefined;\n}\n\n/**\n * Resolve SAP BTP credentials from explicit overrides, falling back to the\n * repo-wide `SAP_EMAIL` / `SAP_PASSWORD` environment variables. Returns\n * `undefined` when either half is missing.\n */\nexport function readSapCredentials(\n overrides?: SapCredentialOverrides,\n): SapCredentials | undefined {\n const email = overrides?.email ?? readEnv(\"SAP_EMAIL\");\n const password = overrides?.password ?? readEnv(\"SAP_PASSWORD\");\n if (email === undefined || password === undefined) {\n return undefined;\n }\n return { email, password };\n}\n","export type CfHanaErrorCode =\n | \"CONFIG\"\n | \"CREDENTIALS_NOT_FOUND\"\n | \"AMBIGUOUS_BINDING\"\n | \"CONNECTION\"\n | \"QUERY\"\n | \"BACKUP_REQUIRED\"\n | \"READ_ONLY_VIOLATION\"\n | \"DESTRUCTIVE_BLOCKED\"\n | \"TIMEOUT\"\n | \"POOL_CLOSED\";\n\nexport interface CfHanaErrorOptions {\n readonly cause?: unknown;\n}\n\nexport interface QueryErrorOptions extends CfHanaErrorOptions {\n readonly sqlState?: string;\n readonly databaseCode?: number;\n}\n\n/** Base error for every failure surfaced by `@saptools/cf-hana`. */\nexport class CfHanaError extends Error {\n readonly code: CfHanaErrorCode;\n\n constructor(code: CfHanaErrorCode, message: string, options?: CfHanaErrorOptions) {\n super(message, options);\n this.name = \"CfHanaError\";\n this.code = code;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** No HANA credentials could be resolved for the requested selector. */\nexport class CredentialsNotFoundError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"CREDENTIALS_NOT_FOUND\", message, options);\n this.name = \"CredentialsNotFoundError\";\n }\n}\n\n/** A SQL statement failed on the HANA server. */\nexport class QueryError extends CfHanaError {\n readonly sqlState: string | undefined;\n readonly databaseCode: number | undefined;\n\n constructor(message: string, options?: QueryErrorOptions) {\n super(\"QUERY\", message, options);\n this.name = \"QueryError\";\n this.sqlState = options?.sqlState;\n this.databaseCode = options?.databaseCode;\n }\n}\n\n/** A CLI write was refused because its required pre-image could not be preserved. */\nexport class BackupRequiredError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"BACKUP_REQUIRED\", message, options);\n this.name = \"BackupRequiredError\";\n }\n}\n\nfunction isDatabaseErrorShape(error: unknown): error is { readonly code?: unknown } {\n return typeof error === \"object\" && error !== null && \"code\" in error;\n}\n\nfunction safeDatabaseCode(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isSafeInteger(value)) {\n return value;\n }\n if (typeof value !== \"string\" || !/^\\d+$/.test(value)) {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) ? parsed : undefined;\n}\n\n/** Extract a numeric HANA database error code from wrapped query failures. */\nexport function databaseCode(error: unknown): number | undefined {\n if (error instanceof QueryError) {\n return error.databaseCode ?? databaseCode(error.cause);\n }\n if (isDatabaseErrorShape(error)) {\n return safeDatabaseCode(error.code);\n }\n return undefined;\n}\n\n/** A write/DDL statement was issued on a read-only client. */\nexport class ReadOnlyViolationError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"READ_ONLY_VIOLATION\", message, options);\n this.name = \"ReadOnlyViolationError\";\n }\n}\n\n/** A destructive statement was blocked because it was not explicitly allowed. */\nexport class DestructiveStatementError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"DESTRUCTIVE_BLOCKED\", message, options);\n this.name = \"DestructiveStatementError\";\n }\n}\n\n/** Narrow an unknown thrown value to a human-readable message. */\nexport function errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n return String(error);\n}\n","/** HANA column types whose Buffer values represent text rather than binary bytes. */\nconst TEXT_LOB_TYPES = new Set([\"CLOB\", \"NCLOB\"]);\n\nfunction normalizeTypeName(typeName: string | undefined): string {\n return typeName?.trim().toUpperCase() ?? \"\";\n}\n\nexport function isTextLobType(typeName: string | undefined): boolean {\n return TEXT_LOB_TYPES.has(normalizeTypeName(typeName));\n}\n","import { isTextLobType } from \"./lob.js\";\nimport { previewCell } from \"./result-preview.js\";\nimport type { OutputFormat, QueryResult, QueryResultColumn, SqlParam } from \"./types.js\";\n\ntype JsonCell = string | number | boolean | null;\n\nfunction cellText(value: SqlParam, nullText: string, column?: QueryResultColumn): string {\n if (value === null) {\n return nullText;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (Buffer.isBuffer(value)) {\n return isTextLobType(column?.typeName)\n ? value.toString(\"utf8\")\n : `0x${value.toString(\"hex\")}`;\n }\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n return typeof value === \"number\" ? value.toString() : value;\n}\n\nfunction serializeCell(value: SqlParam, column?: QueryResultColumn): JsonCell {\n if (value === null) {\n return null;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (Buffer.isBuffer(value)) {\n return isTextLobType(column?.typeName)\n ? value.toString(\"utf8\")\n : `0x${value.toString(\"hex\")}`;\n }\n return value;\n}\n\nfunction csvEscape(text: string): string {\n if (/[\",\\r\\n]/.test(text)) {\n return `\"${text.replace(/\"/g, '\"\"')}\"`;\n }\n return text;\n}\n\nexport interface CompactCsv {\n readonly text: string;\n readonly truncatedCells: number;\n}\n\n/** Render a result as an aligned ASCII table. */\nexport function formatTable(result: QueryResult): string {\n if (result.columns.length === 0) {\n return `(${String(result.rowCount)} row(s) affected)`;\n }\n\n const headers = result.columns.map((column) => column.name);\n const rows = result.rows.map((row) =>\n result.columns.map((column) => cellText(row[column.name] ?? null, \"NULL\", column)),\n );\n const widths = headers.map((header, index) => {\n const widest = rows.reduce(\n (max, cells) => Math.max(max, (cells[index] ?? \"\").length),\n header.length,\n );\n return widest;\n });\n\n const renderRow = (cells: readonly string[]): string =>\n cells.map((cell, index) => cell.padEnd(widths[index] ?? 0)).join(\" | \");\n const separator = widths.map((width) => \"-\".repeat(width)).join(\"-+-\");\n const body = rows.map((cells) => renderRow(cells));\n\n return [renderRow(headers), separator, ...body].join(\"\\n\");\n}\n\n/** Render a result's rows as pretty-printed JSON. */\nexport function formatJson(result: QueryResult): string {\n const rows = result.rows.map((row) => {\n const serialized: Record<string, JsonCell> = {};\n for (const [key, value] of Object.entries(row)) {\n const column = result.columns.find((item) => item.name === key);\n serialized[key] = serializeCell(value, column);\n }\n return serialized;\n });\n return JSON.stringify(rows, null, 2);\n}\n\nfunction formatJsonCompact(result: QueryResult, preferredColumn?: string): string {\n const singleColumn = result.columns.length === 1 ? result.columns[0]?.name : void 0;\n const columnName = preferredColumn ?? singleColumn;\n if (columnName === undefined) {\n return formatJson(result);\n }\n const column = result.columns.find((item) => item.name === columnName);\n const values = result.rows.map((row) => serializeCell(row[columnName] ?? null, column));\n return JSON.stringify(values, null, 2);\n}\n\n/** Render a result as RFC 4180 CSV. */\nexport function formatCsv(result: QueryResult): string {\n const headers = result.columns.map((column) => column.name);\n const lines = [headers.map((header) => csvEscape(header)).join(\",\")];\n for (const row of result.rows) {\n lines.push(\n result.columns\n .map((column) => csvEscape(cellText(row[column.name] ?? null, \"\", column)))\n .join(\",\"),\n );\n }\n return lines.join(\"\\r\\n\");\n}\n\n/** Render bounded CSV for CLI SELECT output without mutating the source result. */\nexport function formatCompactCsv(result: QueryResult, cellLimit: number): CompactCsv {\n const headers = result.columns.map((column) => column.name);\n const lines = [headers.map((header) => csvEscape(header)).join(\",\")];\n let truncatedCells = 0;\n for (const row of result.rows) {\n const cells = result.columns.map((column) => {\n const preview = previewCell(row[column.name] ?? null, cellLimit, column.typeName);\n if (preview.truncated) {\n truncatedCells += 1;\n }\n return csvEscape(preview.text);\n });\n lines.push(cells.join(\",\"));\n }\n return { text: lines.join(\"\\r\\n\"), truncatedCells };\n}\n\n/** Render a query result in the requested output format. */\nexport function formatResult(\n result: QueryResult,\n format: OutputFormat,\n compactColumn?: string,\n): string {\n switch (format) {\n case \"table\":\n return formatTable(result);\n case \"json\":\n return formatJson(result);\n case \"json-compact\":\n return formatJsonCompact(result, compactColumn);\n case \"csv\":\n return formatCsv(result);\n }\n}\n","export interface TopLevelToken {\n readonly keyword: string;\n readonly start: number;\n readonly end: number;\n}\n\nexport interface ParsedTarget {\n readonly sql: string;\n readonly reference: string;\n readonly end: number;\n}\n\nfunction isIdentifierChar(char: string | undefined): boolean {\n return char !== undefined && /[A-Za-z0-9_$#]/.test(char);\n}\n\nfunction skipQuotedText(sql: string, index: number): number {\n const quote = sql[index];\n let cursor = index + 1;\n while (cursor < sql.length) {\n if (sql[cursor] === quote) {\n if (sql[cursor + 1] === quote) {\n cursor += 2;\n continue;\n }\n return cursor + 1;\n }\n cursor += 1;\n }\n return cursor;\n}\n\nfunction skipLineComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && sql[cursor] !== \"\\n\") {\n cursor += 1;\n }\n return cursor;\n}\n\nfunction skipBlockComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && !(sql[cursor] === \"*\" && sql[cursor + 1] === \"/\")) {\n cursor += 1;\n }\n return Math.min(cursor + 2, sql.length);\n}\n\nfunction skipNonCode(sql: string, index: number): number | undefined {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n return skipQuotedText(sql, index);\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n return skipLineComment(sql, index);\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n return skipBlockComment(sql, index);\n }\n return undefined;\n}\n\nexport function skipTrivia(sql: string, start: number, end: number): number {\n let index = start;\n while (index < end) {\n if (/\\s/.test(sql.charAt(index))) {\n index += 1;\n continue;\n }\n if (sql[index] === \"-\" && sql[index + 1] === \"-\") {\n index = skipLineComment(sql, index);\n continue;\n }\n if (sql[index] === \"/\" && sql[index + 1] === \"*\") {\n index = skipBlockComment(sql, index);\n continue;\n }\n break;\n }\n return index;\n}\n\nexport function readIdentifierPart(\n sql: string,\n start: number,\n end: number,\n): { readonly sql: string; readonly end: number } | undefined {\n const index = skipTrivia(sql, start, end);\n if (sql[index] === '\"') {\n const next = skipQuotedText(sql, index);\n return next <= end && sql[next - 1] === '\"'\n ? { sql: sql.slice(index, next), end: next }\n : undefined;\n }\n if (!/[A-Za-z_#$]/.test(sql.charAt(index))) {\n return undefined;\n }\n let next = index + 1;\n while (next < end && /[A-Za-z0-9_#$]/.test(sql.charAt(next))) {\n next += 1;\n }\n return { sql: sql.slice(index, next), end: next };\n}\n\nexport function readQualifiedTarget(\n sql: string,\n start: number,\n end: number,\n): ParsedTarget | undefined {\n const first = readIdentifierPart(sql, start, end);\n if (first === undefined) {\n return undefined;\n }\n const parts = [first.sql];\n let cursor = first.end;\n while (parts.length < 3) {\n const dot = skipTrivia(sql, cursor, end);\n if (sql[dot] !== \".\") {\n break;\n }\n const part = readIdentifierPart(sql, dot + 1, end);\n if (part === undefined) {\n return undefined;\n }\n parts.push(part.sql);\n cursor = part.end;\n }\n return { sql: parts.join(\".\"), reference: parts.at(-1) ?? first.sql, end: cursor };\n}\n\nexport function topLevelTokens(sql: string): readonly TopLevelToken[] {\n const tokens: TopLevelToken[] = [];\n let index = 0;\n let depth = 0;\n while (index < sql.length) {\n const skipped = skipNonCode(sql, index);\n if (skipped !== undefined) {\n index = skipped;\n continue;\n }\n const char = sql.charAt(index);\n if (char === \"(\") {\n depth += 1;\n index += 1;\n continue;\n }\n if (char === \")\") {\n depth = Math.max(0, depth - 1);\n index += 1;\n continue;\n }\n if (!/[A-Za-z_#$]/.test(char)) {\n index += 1;\n continue;\n }\n let end = index + 1;\n while (end < sql.length && /[A-Za-z0-9_#$]/.test(sql.charAt(end))) {\n end += 1;\n }\n if (depth === 0) {\n tokens.push({ keyword: sql.slice(index, end).toUpperCase(), start: index, end });\n }\n index = end;\n }\n return tokens;\n}\n\nexport function findToken(\n tokens: readonly TopLevelToken[],\n keyword: string,\n start = 0,\n): number | undefined {\n for (let index = start; index < tokens.length; index += 1) {\n if (tokens[index]?.keyword === keyword) {\n return index;\n }\n }\n return undefined;\n}\n\nfunction keywordMatches(sql: string, index: number, keyword: string): boolean {\n const end = index + keyword.length;\n return (\n sql.slice(index, end).toUpperCase() === keyword &&\n !isIdentifierChar(sql[index - 1]) &&\n !isIdentifierChar(sql[end])\n );\n}\n\nexport function findTopLevelKeyword(\n sql: string,\n keyword: string,\n startIndex = 0,\n): number | undefined {\n let index = startIndex;\n let depth = 0;\n while (index < sql.length) {\n const skipped = skipNonCode(sql, index);\n if (skipped !== undefined) {\n index = skipped;\n continue;\n }\n const char = sql[index];\n if (char === \"(\") {\n depth += 1;\n } else if (char === \")\" && depth > 0) {\n depth -= 1;\n } else if (depth === 0 && keywordMatches(sql, index, keyword)) {\n return index;\n }\n index += 1;\n }\n return undefined;\n}\n\nexport function findTopLevelChar(\n sql: string,\n target: string,\n startIndex: number,\n endIndex: number,\n): number | undefined {\n let index = startIndex;\n let depth = 0;\n while (index < endIndex) {\n const skipped = skipNonCode(sql, index);\n if (skipped !== undefined) {\n index = skipped;\n continue;\n }\n const char = sql[index];\n if (char === target && depth === 0) {\n return index;\n }\n if (char === \"(\") {\n depth += 1;\n } else if (char === \")\" && depth > 0) {\n depth -= 1;\n }\n index += 1;\n }\n return undefined;\n}\n","import { QueryError } from \"./errors.js\";\nimport type { SqlParam, StatementKind } from \"./types.js\";\n\nconst SELECT_KEYWORDS = new Set([\"SELECT\", \"WITH\"]);\nconst DML_KEYWORDS = new Set([\"INSERT\", \"UPDATE\", \"DELETE\", \"MERGE\", \"UPSERT\", \"REPLACE\"]);\nconst DDL_KEYWORDS = new Set([\"CREATE\", \"DROP\", \"ALTER\", \"TRUNCATE\", \"RENAME\", \"COMMENT\"]);\n\n/** The leading SQL keyword, upper-cased, skipping comments and whitespace. */\nexport function firstKeyword(sql: string): string {\n let index = 0;\n while (index < sql.length) {\n const char = sql.charAt(index);\n if (char.trim().length === 0) {\n index += 1;\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n index += 2;\n while (index < sql.length && sql[index] !== \"\\n\") {\n index += 1;\n }\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n const commentEnd = sql.indexOf(\"*/\", index + 2);\n if (commentEnd === -1) {\n return \"\";\n }\n index = commentEnd + 2;\n continue;\n }\n break;\n }\n\n let keywordEnd = index;\n while (keywordEnd < sql.length) {\n const code = sql.charCodeAt(keywordEnd);\n const isUpperCase = code >= 65 && code <= 90;\n const isLowerCase = code >= 97 && code <= 122;\n if (!isUpperCase && !isLowerCase) {\n break;\n }\n keywordEnd += 1;\n }\n return sql.slice(index, keywordEnd).toUpperCase();\n}\n\n/** Classify a SQL statement by its leading keyword. */\nexport function classifyStatement(sql: string): StatementKind {\n const keyword = firstKeyword(sql);\n if (SELECT_KEYWORDS.has(keyword)) {\n return \"select\";\n }\n if (DML_KEYWORDS.has(keyword)) {\n return \"dml\";\n }\n if (DDL_KEYWORDS.has(keyword)) {\n return \"ddl\";\n }\n return \"unknown\";\n}\n\n/** Quote a SQL identifier (table/column name) for safe interpolation. */\nexport function quoteIdentifier(identifier: string): string {\n if (identifier.length === 0) {\n throw new QueryError(\"A SQL identifier must not be empty\");\n }\n if (identifier.includes(\"\\0\")) {\n throw new QueryError(\"A SQL identifier must not contain a NUL character\");\n }\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\n/** Build a `\"schema\".\"table\"` qualified, quoted name. */\nexport function qualifiedName(schema: string, table: string): string {\n return `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;\n}\n\n/** Count `?` placeholders, skipping string literals, quoted identifiers, and comments. */\nexport function countPlaceholders(sql: string): number {\n let count = 0;\n let index = 0;\n const length = sql.length;\n\n while (index < length) {\n const char = sql[index];\n\n if (char === \"'\" || char === '\"') {\n const quote = char;\n index += 1;\n while (index < length) {\n if (sql[index] === quote) {\n if (sql[index + 1] === quote) {\n index += 2;\n continue;\n }\n index += 1;\n break;\n }\n index += 1;\n }\n continue;\n }\n\n if (char === \"-\" && sql[index + 1] === \"-\") {\n index += 2;\n while (index < length && sql[index] !== \"\\n\") {\n index += 1;\n }\n continue;\n }\n\n if (char === \"/\" && sql[index + 1] === \"*\") {\n index += 2;\n while (index < length && !(sql[index] === \"*\" && sql[index + 1] === \"/\")) {\n index += 1;\n }\n index += 2;\n continue;\n }\n\n if (char === \"?\") {\n count += 1;\n }\n index += 1;\n }\n\n return count;\n}\n\n/** Throw when the number of `?` placeholders does not match the parameter count. */\nexport function assertParamArity(sql: string, params: readonly SqlParam[]): void {\n const expected = countPlaceholders(sql);\n if (expected !== params.length) {\n throw new QueryError(\n `SQL expects ${String(expected)} bound parameter(s) ` +\n `but received ${String(params.length)} value(s)`,\n );\n }\n}\n","import {\n findToken,\n findTopLevelChar,\n findTopLevelKeyword,\n readIdentifierPart,\n readQualifiedTarget,\n skipTrivia,\n topLevelTokens,\n} from \"./003-backup-sql-parser.js\";\nimport type { ParsedTarget, TopLevelToken } from \"./003-backup-sql-parser.js\";\nimport { BackupRequiredError, QueryError } from \"./errors.js\";\nimport { assertParamArity, countPlaceholders, firstKeyword } from \"./statements.js\";\nimport type { SqlParam } from \"./types.js\";\n\nexport type WriteBackupOperation = \"update\" | \"upsert\" | \"replace\" | \"merge\" | \"delete\";\n\nexport interface WriteBackupPlan {\n readonly operation: WriteBackupOperation;\n readonly statementSql: string;\n readonly selectSql: string;\n readonly selectParams: readonly SqlParam[];\n}\n\ninterface ParsedMerge {\n readonly tokens: readonly TopLevelToken[];\n readonly into: TopLevelToken;\n readonly using: TopLevelToken;\n readonly on: TopLevelToken;\n readonly target: ParsedTarget;\n readonly clauseIndexes: readonly number[];\n readonly matchedIndexes: readonly number[];\n readonly targetClause: string;\n readonly sourceClause: string;\n readonly onCondition: string;\n}\n\ninterface ParsedMatchedClause {\n readonly clauseStart: number;\n readonly matchedCondition: string;\n readonly conditionParams: readonly SqlParam[];\n}\n\ninterface MatchedActionTokens {\n readonly thenToken: TopLevelToken;\n readonly conditionToken: TopLevelToken | undefined;\n readonly clauseStart: number;\n}\n\ntype WriteKeyword = \"UPDATE\" | \"UPSERT\" | \"REPLACE\" | \"MERGE\" | \"DELETE\";\n\nconst WRITE_KEYWORDS = new Set<string>([\n \"UPDATE\",\n \"UPSERT\",\n \"REPLACE\",\n \"MERGE\",\n \"DELETE\",\n]);\nconst MERGE_MODIFY_ACTIONS = new Set<string>([\"UPDATE\", \"DELETE\"]);\n\nfunction trimStatementSql(sql: string): string {\n const trimmed = sql.trim();\n let end = trimmed.length;\n while (end > 0 && trimmed.charAt(end - 1) === \";\") {\n end -= 1;\n }\n return trimmed.slice(0, end).trim();\n}\n\nfunction isMergeClauseStart(tokens: readonly TopLevelToken[], index: number): boolean {\n if (tokens[index]?.keyword !== \"WHEN\") {\n return false;\n }\n return (\n tokens[index + 1]?.keyword === \"MATCHED\" ||\n (tokens[index + 1]?.keyword === \"NOT\" && tokens[index + 2]?.keyword === \"MATCHED\")\n );\n}\n\nfunction mergeClauseIndexes(\n tokens: readonly TopLevelToken[],\n start: number,\n): readonly number[] {\n const indexes: number[] = [];\n for (let index = start; index < tokens.length; index += 1) {\n if (isMergeClauseStart(tokens, index)) {\n indexes.push(index);\n }\n }\n return indexes;\n}\n\nfunction selectParamsAfterWhere(\n statementSql: string,\n whereIndex: number,\n params: readonly SqlParam[],\n): readonly SqlParam[] {\n return params.slice(countPlaceholders(statementSql.slice(0, whereIndex)));\n}\n\nfunction buildSelectPlan(\n operation: WriteBackupOperation,\n statementSql: string,\n targetSql: string,\n whereIndex: number | undefined,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const target = targetSql.trim();\n if (target.length === 0) {\n throw new QueryError(`${operation.toUpperCase()} backup requires a target table`);\n }\n if (whereIndex === undefined) {\n return { operation, statementSql, selectSql: `SELECT * FROM ${target}`, selectParams: [] };\n }\n\n const whereSql = statementSql.slice(whereIndex + \"WHERE\".length).trim();\n if (whereSql.length === 0) {\n throw new QueryError(`${operation.toUpperCase()} backup requires a non-empty WHERE clause`);\n }\n return {\n operation,\n statementSql,\n selectSql: `SELECT * FROM ${target} WHERE ${whereSql}`,\n selectParams: selectParamsAfterWhere(statementSql, whereIndex, params),\n };\n}\n\nfunction buildUpdateBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const updateIndex = findTopLevelKeyword(statementSql, \"UPDATE\");\n const setIndex =\n updateIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"SET\", updateIndex + \"UPDATE\".length);\n if (updateIndex === undefined || setIndex === undefined) {\n throw new QueryError(\"UPDATE backup requires UPDATE <target> SET syntax\");\n }\n\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", setIndex + \"SET\".length);\n return buildSelectPlan(\n \"update\",\n statementSql,\n statementSql.slice(updateIndex + \"UPDATE\".length, setIndex),\n whereIndex,\n params,\n );\n}\n\nfunction buildUpsertBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n keyword: \"UPSERT\" | \"REPLACE\",\n): WriteBackupPlan {\n const operation = keyword === \"UPSERT\" ? \"upsert\" : \"replace\";\n const keywordIndex = findTopLevelKeyword(statementSql, keyword);\n const target =\n keywordIndex === undefined\n ? undefined\n : readQualifiedTarget(statementSql, keywordIndex + keyword.length, statementSql.length);\n if (keywordIndex === undefined || target === undefined) {\n throw new BackupRequiredError(\n `${keyword} write refused: cannot derive a trustworthy backup target`,\n );\n }\n const valuesIndex = findTopLevelKeyword(statementSql, \"VALUES\", target.end);\n if (valuesIndex === undefined) {\n const selectIndex = findTopLevelKeyword(statementSql, \"SELECT\", target.end);\n const withIndex = findTopLevelKeyword(statementSql, \"WITH\", target.end);\n if (selectIndex === undefined && withIndex === undefined) {\n throw new BackupRequiredError(\n `${keyword} write refused: expected VALUES, WITH PRIMARY KEY, or a subquery`,\n );\n }\n return buildSelectPlan(operation, statementSql, target.sql, undefined, params);\n }\n\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", valuesIndex + \"VALUES\".length);\n return buildSelectPlan(operation, statementSql, target.sql, whereIndex, params);\n}\n\nfunction mergeTargetReference(\n statementSql: string,\n target: ParsedTarget,\n usingStart: number,\n): string | undefined {\n let suffix = statementSql.slice(target.end, usingStart).trim();\n if (suffix.length === 0) {\n return target.reference;\n }\n if (/^PARTITION\\b/i.test(suffix)) {\n const open = suffix.indexOf(\"(\");\n if (open === -1) {\n return undefined;\n }\n const close = findTopLevelChar(suffix, \")\", open + 1, suffix.length);\n if (close === undefined) {\n return undefined;\n }\n suffix = suffix.slice(close + 1).trim();\n if (suffix.length === 0) {\n return target.reference;\n }\n }\n suffix = suffix.replace(/^AS\\b/i, \"\").trim();\n const alias = readIdentifierPart(suffix, 0, suffix.length);\n if (alias === undefined || skipTrivia(suffix, alias.end, suffix.length) !== suffix.length) {\n return undefined;\n }\n return alias.sql;\n}\n\nfunction paramsInRange(\n sql: string,\n params: readonly SqlParam[],\n start: number,\n end: number,\n): readonly SqlParam[] {\n const offset = countPlaceholders(sql.slice(0, start));\n const length = countPlaceholders(sql.slice(start, end));\n return params.slice(offset, offset + length);\n}\n\nfunction wholeTargetPlan(\n operation: WriteBackupOperation,\n statementSql: string,\n target: ParsedTarget,\n): WriteBackupPlan {\n return buildSelectPlan(operation, statementSql, target.sql, undefined, []);\n}\n\nfunction readRequiredMergeToken(\n tokens: readonly TopLevelToken[],\n keyword: string,\n start: number,\n): { readonly index: number; readonly token: TopLevelToken } {\n const index = findToken(tokens, keyword, start);\n const token = index === undefined ? undefined : tokens[index];\n if (index === undefined || token === undefined) {\n throw new BackupRequiredError(\n \"MERGE write refused: cannot derive a trustworthy backup target\",\n );\n }\n return { index, token };\n}\n\nfunction parseMerge(statementSql: string): ParsedMerge {\n const tokens = topLevelTokens(statementSql);\n const into = readRequiredMergeToken(tokens, \"INTO\", 1);\n const using = readRequiredMergeToken(tokens, \"USING\", into.index + 1);\n const on = readRequiredMergeToken(tokens, \"ON\", using.index + 1);\n const target = readQualifiedTarget(statementSql, into.token.end, using.token.start);\n if (target === undefined) {\n throw new BackupRequiredError(\n \"MERGE write refused: cannot derive a trustworthy backup target\",\n );\n }\n const clauseIndexes = mergeClauseIndexes(tokens, on.index + 1);\n if (clauseIndexes.length === 0) {\n throw new BackupRequiredError(\"MERGE write refused: no supported WHEN clause was found\");\n }\n const firstClause = tokens[clauseIndexes[0] ?? 0];\n return {\n tokens,\n into: into.token,\n using: using.token,\n on: on.token,\n target,\n clauseIndexes,\n matchedIndexes: clauseIndexes.filter((index) => tokens[index + 1]?.keyword === \"MATCHED\"),\n targetClause: statementSql.slice(into.token.end, using.token.start).trim(),\n sourceClause: statementSql.slice(using.token.end, on.token.start).trim(),\n onCondition: statementSql.slice(on.token.end, firstClause?.start).trim(),\n };\n}\n\nfunction readMatchedActionTokens(\n tokens: readonly TopLevelToken[],\n matchedIndex: number,\n): MatchedActionTokens | undefined {\n const thenIndex = findToken(tokens, \"THEN\", matchedIndex + 2);\n if (thenIndex === undefined) {\n return undefined;\n }\n const thenToken = tokens[thenIndex];\n const actionToken = tokens[thenIndex + 1];\n const matchedToken = tokens[matchedIndex + 1];\n if (thenToken === undefined || actionToken === undefined || matchedToken === undefined) {\n return undefined;\n }\n if (!MERGE_MODIFY_ACTIONS.has(actionToken.keyword)) {\n return undefined;\n }\n const clauseToken = tokens[matchedIndex];\n return {\n thenToken,\n conditionToken: tokens[matchedIndex + 2],\n clauseStart: clauseToken === undefined ? 0 : clauseToken.start,\n };\n}\n\nfunction parseMatchedClause(\n statementSql: string,\n params: readonly SqlParam[],\n tokens: readonly TopLevelToken[],\n matchedIndex: number,\n): ParsedMatchedClause | undefined {\n const action = readMatchedActionTokens(tokens, matchedIndex);\n if (action?.conditionToken === undefined) {\n return undefined;\n }\n if (action.conditionToken.keyword === \"THEN\") {\n return { clauseStart: action.clauseStart, matchedCondition: \"\", conditionParams: [] };\n }\n if (action.conditionToken.keyword !== \"AND\") {\n return undefined;\n }\n return {\n clauseStart: action.clauseStart,\n matchedCondition: statementSql.slice(action.conditionToken.end, action.thenToken.start).trim(),\n conditionParams: paramsInRange(\n statementSql,\n params,\n action.conditionToken.end,\n action.thenToken.start,\n ),\n };\n}\n\nfunction buildExactMergePlan(\n statementSql: string,\n params: readonly SqlParam[],\n merge: ParsedMerge,\n matchedIndex: number,\n): WriteBackupPlan | undefined {\n const targetReference = mergeTargetReference(statementSql, merge.target, merge.using.start);\n const matchedClause = parseMatchedClause(statementSql, params, merge.tokens, matchedIndex);\n if (targetReference === undefined || matchedClause === undefined) {\n return undefined;\n }\n const sourceParams = paramsInRange(\n statementSql,\n params,\n merge.using.end,\n matchedClause.clauseStart,\n );\n const conditionSql = matchedClause.matchedCondition.length === 0\n ? \"\"\n : ` AND (${matchedClause.matchedCondition})`;\n return {\n operation: \"merge\",\n statementSql,\n selectSql:\n `SELECT ${targetReference}.* FROM ${merge.targetClause} ` +\n `WHERE EXISTS (SELECT 1 FROM ${merge.sourceClause} ` +\n `WHERE (${merge.onCondition})${conditionSql})`,\n selectParams: [...sourceParams, ...matchedClause.conditionParams],\n };\n}\n\nfunction buildMergeBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan | undefined {\n const merge = parseMerge(statementSql);\n if (merge.matchedIndexes.length === 0) {\n return undefined;\n }\n if (merge.matchedIndexes.length > 1) {\n return wholeTargetPlan(\"merge\", statementSql, merge.target);\n }\n if (merge.sourceClause.length === 0 || merge.onCondition.length === 0) {\n return wholeTargetPlan(\"merge\", statementSql, merge.target);\n }\n const matchedIndex = merge.matchedIndexes[0] ?? 0;\n return (\n buildExactMergePlan(statementSql, params, merge, matchedIndex) ??\n wholeTargetPlan(\"merge\", statementSql, merge.target)\n );\n}\n\nfunction buildDeleteBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const deleteIndex = findTopLevelKeyword(statementSql, \"DELETE\");\n const fromIndex =\n deleteIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"FROM\", deleteIndex + \"DELETE\".length);\n if (deleteIndex === undefined || fromIndex === undefined) {\n throw new QueryError(\"DELETE backup requires DELETE FROM <target> syntax\");\n }\n\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", fromIndex + \"FROM\".length);\n const targetEnd = whereIndex ?? statementSql.length;\n return buildSelectPlan(\n \"delete\",\n statementSql,\n statementSql.slice(fromIndex + \"FROM\".length, targetEnd),\n whereIndex,\n params,\n );\n}\n\nfunction isWriteKeyword(keyword: string): keyword is WriteKeyword {\n return WRITE_KEYWORDS.has(keyword);\n}\n\nfunction buildMergeWriteBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan | undefined {\n const secondKeyword = topLevelTokens(statementSql)[1]?.keyword;\n if (secondKeyword === \"DELTA\") {\n return undefined;\n }\n if (secondKeyword !== \"INTO\") {\n throw new BackupRequiredError(\"MERGE write refused: expected MERGE INTO syntax\");\n }\n return buildMergeBackupPlan(statementSql, params);\n}\n\nfunction dispatchWriteBackupPlan(\n keyword: WriteKeyword,\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan | undefined {\n switch (keyword) {\n case \"UPDATE\":\n return buildUpdateBackupPlan(statementSql, params);\n case \"UPSERT\":\n case \"REPLACE\":\n return buildUpsertBackupPlan(statementSql, params, keyword);\n case \"MERGE\":\n return buildMergeWriteBackupPlan(statementSql, params);\n case \"DELETE\":\n return buildDeleteBackupPlan(statementSql, params);\n }\n}\n\nexport function buildWriteBackupPlan(\n sql: string,\n params: readonly SqlParam[] = [],\n): WriteBackupPlan | undefined {\n const statementSql = trimStatementSql(sql);\n const keyword = firstKeyword(statementSql);\n if (!isWriteKeyword(keyword)) {\n return undefined;\n }\n assertParamArity(statementSql, params);\n return dispatchWriteBackupPlan(keyword, statementSql, params);\n}\n","import { QueryError } from \"./errors.js\";\nimport { qualifiedName, quoteIdentifier } from \"./statements.js\";\nimport type { BuiltStatement, SelectSpec, SqlParam } from \"./types.js\";\n\ninterface WhereClause {\n readonly clause: string;\n readonly params: readonly SqlParam[];\n}\n\nfunction buildWhere(where: Readonly<Record<string, SqlParam>> | undefined): WhereClause {\n if (where === undefined) {\n return { clause: \"\", params: [] };\n }\n const entries = Object.entries(where);\n if (entries.length === 0) {\n return { clause: \"\", params: [] };\n }\n const conditions = entries.map(([column]) => `${quoteIdentifier(column)} = ?`);\n return {\n clause: ` WHERE ${conditions.join(\" AND \")}`,\n params: entries.map(([, value]) => value),\n };\n}\n\n/** Build a parameterized `SELECT` statement from a typed spec. */\nexport function buildSelect(spec: SelectSpec): BuiltStatement {\n const columns =\n spec.columns === undefined || spec.columns.length === 0\n ? \"*\"\n : spec.columns.map((column) => quoteIdentifier(column)).join(\", \");\n const where = buildWhere(spec.where);\n const clauses: string[] = [\n `SELECT ${columns} FROM ${qualifiedName(spec.schema, spec.table)}${where.clause}`,\n ];\n\n if (spec.orderBy !== undefined && spec.orderBy.length > 0) {\n clauses.push(`ORDER BY ${spec.orderBy.map((column) => quoteIdentifier(column)).join(\", \")}`);\n }\n if (spec.limit !== undefined) {\n clauses.push(`LIMIT ${String(spec.limit)}`);\n }\n if (spec.offset !== undefined) {\n clauses.push(`OFFSET ${String(spec.offset)}`);\n }\n\n return { sql: clauses.join(\" \"), params: where.params };\n}\n\n/** Build a parameterized `SELECT COUNT(*)` statement. */\nexport function buildCount(\n spec: Pick<SelectSpec, \"schema\" | \"table\" | \"where\">,\n): BuiltStatement {\n const where = buildWhere(spec.where);\n return {\n sql: `SELECT COUNT(*) AS \"COUNT\" FROM ${qualifiedName(spec.schema, spec.table)}${where.clause}`,\n params: where.params,\n };\n}\n\n/** Build a parameterized single-row `INSERT` statement. */\nexport function buildInsert(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const entries = Object.entries(values);\n if (entries.length === 0) {\n throw new QueryError(\"INSERT requires at least one column value\");\n }\n const columns = entries.map(([column]) => quoteIdentifier(column)).join(\", \");\n const placeholders = entries.map(() => \"?\").join(\", \");\n return {\n sql: `INSERT INTO ${qualifiedName(schema, table)} (${columns}) VALUES (${placeholders})`,\n params: entries.map(([, value]) => value),\n };\n}\n\n/** Build a parameterized `UPDATE` statement. A non-empty `where` is required. */\nexport function buildUpdate(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n where: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const valueEntries = Object.entries(values);\n if (valueEntries.length === 0) {\n throw new QueryError(\"UPDATE requires at least one column value\");\n }\n const whereClause = buildWhere(where);\n if (whereClause.clause === \"\") {\n throw new QueryError(\"UPDATE requires a non-empty WHERE filter to avoid a full-table write\");\n }\n const assignments = valueEntries\n .map(([column]) => `${quoteIdentifier(column)} = ?`)\n .join(\", \");\n return {\n sql: `UPDATE ${qualifiedName(schema, table)} SET ${assignments}${whereClause.clause}`,\n params: [...valueEntries.map(([, value]) => value), ...whereClause.params],\n };\n}\n\n/** Build a parameterized `DELETE` statement. A non-empty `where` is required. */\nexport function buildDelete(\n schema: string,\n table: string,\n where: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const whereClause = buildWhere(where);\n if (whereClause.clause === \"\") {\n throw new QueryError(\"DELETE requires a non-empty WHERE filter to avoid a full-table delete\");\n }\n return {\n sql: `DELETE FROM ${qualifiedName(schema, table)}${whereClause.clause}`,\n params: whereClause.params,\n };\n}\n","import type { Connection } from \"./connection.js\";\nimport type { CatalogObjectInfo } from \"./metadata-cache.js\";\nimport type { ColumnInfo, TableInfo } from \"./types.js\";\n\ninterface SchemaRow {\n readonly SCHEMA_NAME: string;\n}\n\ninterface TableRow {\n readonly SCHEMA_NAME: string;\n readonly TABLE_NAME: string;\n readonly TABLE_TYPE: string;\n}\n\ninterface CatalogObjectRow {\n readonly SCHEMA_NAME: string;\n readonly OBJECT_NAME: string;\n readonly OBJECT_TYPE: \"TABLE\" | \"VIEW\";\n}\n\ninterface ColumnRow {\n readonly COLUMN_NAME: string;\n readonly DATA_TYPE_NAME: string;\n readonly LENGTH: number | null;\n readonly SCALE: number | null;\n readonly IS_NULLABLE: string;\n readonly POSITION: number;\n}\n\nexport interface TableDescription {\n readonly table: TableInfo | undefined;\n readonly columns: readonly ColumnInfo[];\n}\n\n/** List every schema visible to the current user. */\nexport async function listSchemas(connection: Connection): Promise<readonly string[]> {\n const result = await connection.query<SchemaRow>(\n \"SELECT SCHEMA_NAME FROM SYS.SCHEMAS ORDER BY SCHEMA_NAME\",\n [],\n { autoLimit: false },\n );\n return result.rows.map((row) => row.SCHEMA_NAME);\n}\n\n/** List the tables in a schema. */\nexport async function listTables(\n connection: Connection,\n schema: string,\n): Promise<readonly TableInfo[]> {\n const result = await connection.query<TableRow>(\n \"SELECT SCHEMA_NAME, TABLE_NAME, TABLE_TYPE FROM SYS.TABLES \" +\n \"WHERE SCHEMA_NAME = ? ORDER BY TABLE_NAME\",\n [schema],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n schema: row.SCHEMA_NAME,\n name: row.TABLE_NAME,\n type: row.TABLE_TYPE,\n rowCount: undefined,\n }));\n}\n\n/** List table and view names in a schema for typo recovery suggestions. */\nexport async function listCatalogObjects(\n connection: Connection,\n schema: string,\n): Promise<readonly CatalogObjectInfo[]> {\n const result = await connection.query<CatalogObjectRow>(\n \"SELECT SCHEMA_NAME, TABLE_NAME AS OBJECT_NAME, 'TABLE' AS OBJECT_TYPE FROM SYS.TABLES \" +\n \"WHERE SCHEMA_NAME = ? UNION ALL \" +\n \"SELECT SCHEMA_NAME, VIEW_NAME AS OBJECT_NAME, 'VIEW' AS OBJECT_TYPE FROM SYS.VIEWS \" +\n \"WHERE SCHEMA_NAME = ? ORDER BY OBJECT_NAME\",\n [schema, schema],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n schema: row.SCHEMA_NAME,\n name: row.OBJECT_NAME,\n type: row.OBJECT_TYPE,\n }));\n}\n\n/** List the columns of a table, ordered by position. */\nexport async function listColumns(\n connection: Connection,\n schema: string,\n table: string,\n): Promise<readonly ColumnInfo[]> {\n const result = await connection.query<ColumnRow>(\n \"SELECT COLUMN_NAME, DATA_TYPE_NAME, LENGTH, SCALE, IS_NULLABLE, POSITION \" +\n \"FROM SYS.TABLE_COLUMNS WHERE SCHEMA_NAME = ? AND TABLE_NAME = ? ORDER BY POSITION\",\n [schema, table],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n name: row.COLUMN_NAME,\n dataType: row.DATA_TYPE_NAME,\n length: row.LENGTH ?? undefined,\n scale: row.SCALE ?? undefined,\n nullable: row.IS_NULLABLE === \"TRUE\",\n position: row.POSITION,\n }));\n}\n\n/** Describe a table: its catalog entry plus its columns. */\nexport async function describeTable(\n connection: Connection,\n schema: string,\n table: string,\n): Promise<TableDescription> {\n const tables = await listTables(connection, schema);\n const columns = await listColumns(connection, schema, table);\n return {\n table: tables.find((info) => info.name === table),\n columns,\n };\n}\n","import { execFile } from \"node:child_process\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nimport type { HanaBinding } from \"./types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nconst MAX_BUFFER = 16 * 1024 * 1024;\nconst DEFAULT_TIMEOUT_MS = 60_000;\nconst CF_RETRY_ATTEMPTS = 3;\nconst CF_RETRY_BASE_DELAY_MS = 500;\n\n/** Minimal context for an isolated CF CLI invocation. */\nexport interface CfExecContext {\n readonly cfHome: string;\n}\n\n/** Data from `cf target`. */\nexport interface CurrentCfTarget {\n readonly apiEndpoint: string;\n readonly orgName: string;\n readonly spaceName: string;\n readonly regionKey?: string;\n}\n\n/** Application identity embedded in the same `cf env` response as service credentials. */\nexport interface CfEnvApplicationIdentity {\n readonly apiEndpoint: string;\n readonly orgName: string;\n readonly spaceName: string;\n readonly appName: string;\n}\n\nconst REGION_API_MAP: Record<string, string> = {\n ae01: \"https://api.cf.ae01.hana.ondemand.com\",\n ap01: \"https://api.cf.ap01.hana.ondemand.com\",\n ap10: \"https://api.cf.ap10.hana.ondemand.com\",\n ap11: \"https://api.cf.ap11.hana.ondemand.com\",\n ap12: \"https://api.cf.ap12.hana.ondemand.com\",\n ap20: \"https://api.cf.ap20.hana.ondemand.com\",\n ap21: \"https://api.cf.ap21.hana.ondemand.com\",\n ap30: \"https://api.cf.ap30.hana.ondemand.com\",\n ap31: \"https://api.cf.ap31.hana.ondemand.com\",\n br10: \"https://api.cf.br10.hana.ondemand.com\",\n br20: \"https://api.cf.br20.hana.ondemand.com\",\n br30: \"https://api.cf.br30.hana.ondemand.com\",\n ca10: \"https://api.cf.ca10.hana.ondemand.com\",\n ca20: \"https://api.cf.ca20.hana.ondemand.com\",\n ch20: \"https://api.cf.ch20.hana.ondemand.com\",\n cn20: \"https://api.cf.cn20.platform.sapcloud.cn\",\n cn40: \"https://api.cf.cn40.platform.sapcloud.cn\",\n eu01: \"https://api.cf.eu01.hana.ondemand.com\",\n eu02: \"https://api.cf.eu02.hana.ondemand.com\",\n eu10: \"https://api.cf.eu10.hana.ondemand.com\",\n \"eu10-002\": \"https://api.cf.eu10-002.hana.ondemand.com\",\n \"eu10-003\": \"https://api.cf.eu10-003.hana.ondemand.com\",\n \"eu10-004\": \"https://api.cf.eu10-004.hana.ondemand.com\",\n \"eu10-005\": \"https://api.cf.eu10-005.hana.ondemand.com\",\n \"eu10-006\": \"https://api.cf.eu10-006.hana.ondemand.com\",\n eu11: \"https://api.cf.eu11.hana.ondemand.com\",\n eu12: \"https://api.cf.eu12.hana.ondemand.com\",\n eu13: \"https://api.cf.eu13.hana.ondemand.com\",\n eu20: \"https://api.cf.eu20.hana.ondemand.com\",\n \"eu20-001\": \"https://api.cf.eu20-001.hana.ondemand.com\",\n \"eu20-002\": \"https://api.cf.eu20-002.hana.ondemand.com\",\n eu21: \"https://api.cf.eu21.hana.ondemand.com\",\n eu22: \"https://api.cf.eu22.hana.ondemand.com\",\n eu30: \"https://api.cf.eu30.hana.ondemand.com\",\n eu31: \"https://api.cf.eu31.hana.ondemand.com\",\n il30: \"https://api.cf.il30.hana.ondemand.com\",\n in30: \"https://api.cf.in30.hana.ondemand.com\",\n jp01: \"https://api.cf.jp01.hana.ondemand.com\",\n jp10: \"https://api.cf.jp10.hana.ondemand.com\",\n jp20: \"https://api.cf.jp20.hana.ondemand.com\",\n jp30: \"https://api.cf.jp30.hana.ondemand.com\",\n jp31: \"https://api.cf.jp31.hana.ondemand.com\",\n sa30: \"https://api.cf.sa30.hana.ondemand.com\",\n sa31: \"https://api.cf.sa31.hana.ondemand.com\",\n uk20: \"https://api.cf.uk20.hana.ondemand.com\",\n us01: \"https://api.cf.us01.hana.ondemand.com\",\n us02: \"https://api.cf.us02.hana.ondemand.com\",\n us10: \"https://api.cf.us10.hana.ondemand.com\",\n \"us10-001\": \"https://api.cf.us10-001.hana.ondemand.com\",\n \"us10-002\": \"https://api.cf.us10-002.hana.ondemand.com\",\n \"us10-003\": \"https://api.cf.us10-003.hana.ondemand.com\",\n us11: \"https://api.cf.us11.hana.ondemand.com\",\n us20: \"https://api.cf.us20.hana.ondemand.com\",\n us21: \"https://api.cf.us21.hana.ondemand.com\",\n \"us21-001\": \"https://api.cf.us21-001.hana.ondemand.com\",\n us22: \"https://api.cf.us22.hana.ondemand.com\",\n us30: \"https://api.cf.us30.hana.ondemand.com\",\n us32: \"https://api.cf.us32.hana.ondemand.com\",\n};\n\nexport function normalizeSapCfApiEndpoint(apiEndpoint: string): string {\n const trimmed = apiEndpoint.trim();\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n if (/^https:\\/\\/[^/]*:\\d+(?:[/?#]|$)/i.test(trimmed)) {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n if (\n parsed.protocol !== \"https:\" ||\n parsed.username !== \"\" ||\n parsed.password !== \"\" ||\n parsed.port !== \"\" ||\n parsed.pathname.replace(/\\/+$/, \"\") !== \"\" ||\n parsed.search !== \"\" ||\n parsed.hash !== \"\"\n ) {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n const hostname = parsed.hostname.toLowerCase();\n const match = /^api\\.cf\\.([a-z]{2}\\d{2}(?:-\\d{3})?)\\.(hana\\.ondemand\\.com|platform\\.sapcloud\\.cn)$/.exec(hostname);\n if (!match) {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n return `https://${hostname}`;\n}\n\nexport function getApiEndpointForRegion(regionKey: string): string | undefined {\n return REGION_API_MAP[regionKey.trim().toLowerCase()];\n}\n\nexport function getRegionKeyForApi(apiEndpoint: string): string | undefined {\n let normalized: string;\n try {\n normalized = normalizeSapCfApiEndpoint(apiEndpoint);\n } catch {\n return undefined;\n }\n for (const [key, endpoint] of Object.entries(REGION_API_MAP)) {\n if (endpoint.toLowerCase() === normalized) {\n return key;\n }\n }\n return /^https:\\/\\/api\\.cf\\.([a-z]{2}\\d{2}(?:-\\d{3})?)\\.hana\\.ondemand\\.com$/.exec(normalized)?.[1];\n}\n\n/** Run work inside a fresh temporary CF_HOME. Directory is always cleaned. */\nexport async function withCfSession<T>(work: (ctx: CfExecContext) => Promise<T>): Promise<T> {\n const cfHome = await mkdtemp(join(tmpdir(), \"saptools-cf-hana-\"));\n const ctx: CfExecContext = { cfHome };\n try {\n return await work(ctx);\n } finally {\n await rm(cfHome, { recursive: true, force: true });\n }\n}\n\nfunction resolveCfBin(): { bin: string; argsPrefix: readonly string[] } {\n const raw = process.env[\"CF_HANA_CF_BIN\"] ?? \"cf\";\n if (/\\.(?:c|m)?js$/i.test(raw)) {\n return { bin: process.execPath, argsPrefix: [raw] };\n }\n return { bin: raw, argsPrefix: [] };\n}\n\nfunction buildEnv(ctx: CfExecContext, overrides: Record<string, string> = {}): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...process.env, ...overrides };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n env[\"CF_HOME\"] = ctx.cfHome;\n return env;\n}\n\nasync function execWithRetries(\n bin: string,\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n timeoutMs: number = DEFAULT_TIMEOUT_MS\n): Promise<string> {\n let lastErr: unknown;\n for (let attempt = 0; attempt < CF_RETRY_ATTEMPTS; attempt++) {\n try {\n const { stdout } = await execFileAsync(bin, args, {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: timeoutMs,\n killSignal: \"SIGKILL\",\n });\n return stdout;\n } catch (err) {\n lastErr = err;\n \n const e = err as { killed?: boolean; code?: number | string; stderr?: string | Buffer; message?: string };\n const output = `${e.message ?? \"\"} ${e.stderr ? String(e.stderr) : \"\"}`.toLowerCase();\n \n const isTimeout = e.killed === true; \n const isNetworkFlake = \n output.includes(\"error performing request\") ||\n output.includes(\"timeout\") ||\n output.includes(\"connection reset\") ||\n output.includes(\"connection refused\") ||\n output.includes(\"eof\") ||\n output.includes(\"502 bad gateway\") ||\n output.includes(\"503 service unavailable\") ||\n output.includes(\"504 gateway timeout\") ||\n output.includes(\"dial tcp\") ||\n output.includes(\"no such host\");\n \n const isEnoent = e.code === \"ENOENT\";\n if (isEnoent || (!isTimeout && !isNetworkFlake)) {\n throw err; // Fail fast for user errors or missing binary\n }\n\n if (attempt < CF_RETRY_ATTEMPTS - 1) {\n await new Promise((r) => setTimeout(r, CF_RETRY_BASE_DELAY_MS * (attempt + 1)));\n }\n }\n }\n throw lastErr;\n}\n\nasync function runCf(\n args: readonly string[],\n ctx: CfExecContext,\n overrides: Record<string, string> = {},\n): Promise<string> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = buildEnv(ctx, overrides);\n\n try {\n return await execWithRetries(bin, [...argsPrefix, ...args], env);\n } catch (lastErr) {\n const e = lastErr as { stderr?: string | Buffer; message?: string } | undefined;\n const detail = e?.stderr ? String(e.stderr) : (e?.message ?? \"\");\n const cmd = args[0] === \"auth\" ? \"cf auth\" : `cf ${args.join(\" \")}`;\n throw new Error(`${cmd} failed: ${detail}`.trim(), { cause: lastErr });\n }\n}\n\nexport async function cfApi(apiEndpoint: string, ctx: CfExecContext): Promise<void> {\n await runCf([\"api\", apiEndpoint], ctx);\n}\n\n/** Auth using env vars (professional, matches cf-events pattern). */\nexport async function cfAuth(email: string, password: string, ctx: CfExecContext): Promise<void> {\n await runCf([\"auth\"], ctx, {\n CF_USERNAME: email,\n CF_PASSWORD: password,\n });\n}\n\nexport async function cfTargetSpace(\n orgName: string,\n spaceName: string,\n ctx: CfExecContext,\n): Promise<void> {\n await runCf([\"target\", \"-o\", orgName, \"-s\", spaceName], ctx);\n}\n\nexport async function cfEnv(appName: string, ctx: CfExecContext): Promise<string> {\n return await runCf([\"env\", appName], ctx);\n}\n\n/**\n * Direct current user CF context for bare app names.\n * No isolated CF_HOME or forced re-authentication: the current target supplies the app scope.\n */\nexport async function cfEnvDirect(appName: string): Promise<string> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = { ...process.env };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n return await execWithRetries(bin, [...argsPrefix, \"env\", appName], env);\n}\n\nexport async function readCurrentCfTarget(): Promise<CurrentCfTarget | undefined> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = { ...process.env };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n\n try {\n const stdout = await execWithRetries(bin, [...argsPrefix, \"target\"], env);\n return parseCfTargetOutput(stdout);\n } catch {\n return undefined;\n }\n}\n\nexport function parseCfTargetOutput(stdout: string): CurrentCfTarget | undefined {\n const fields = parseTargetFields(stdout);\n const api = fields.get(\"api endpoint\");\n const org = fields.get(\"org\");\n const space = fields.get(\"space\");\n if (!api || !org || !space) {\n return undefined;\n }\n let normalizedApi: string;\n try {\n normalizedApi = normalizeSapCfApiEndpoint(api);\n } catch {\n return undefined;\n }\n const regionKey = getRegionKeyForApi(normalizedApi);\n return {\n apiEndpoint: normalizedApi,\n orgName: org,\n spaceName: space,\n ...(regionKey ? { regionKey } : {}),\n };\n}\n\nfunction parseTargetFields(stdout: string): Map<string, string> {\n const map = new Map<string, string>();\n for (const line of stdout.split(/\\r?\\n/)) {\n const idx = line.indexOf(\":\");\n if (idx < 0) {continue;}\n const key = line.slice(0, idx).trim().toLowerCase();\n const val = line.slice(idx + 1).trim();\n if (key && val) {map.set(key, val);}\n }\n return map;\n}\n\nexport function formatCurrentCfAppSelector(target: CurrentCfTarget, appName: string): string {\n const name = appName.trim();\n if (!name) {throw new Error(\"App name is required.\");}\n const region = target.regionKey ?? \"current\";\n return `${region}/${target.orgName}/${target.spaceName}/${name}`;\n}\n\n/* VCAP parser */\n\nfunction findJsonObjectEnd(source: string, startIndex: number): number {\n let depth = 0;\n let inString = false;\n let escaped = false;\n for (let index = startIndex; index < source.length; index++) {\n const character = source[index];\n if (escaped) {\n escaped = false;\n continue;\n }\n if (inString && character === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (character === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) {continue;}\n if (character === \"{\") {\n depth++;\n continue;\n }\n if (character === \"}\" && --depth === 0) {return index;}\n }\n return -1;\n}\n\nfunction extractVcapApplicationJson(stdout: string): string {\n const marker = \"VCAP_APPLICATION:\";\n const markerIndex = stdout.indexOf(marker);\n if (markerIndex === -1) {\n throw new Error(\"VCAP_APPLICATION section not found in cf env output\");\n }\n const afterMarker = stdout.slice(markerIndex + marker.length);\n const openIndex = afterMarker.indexOf(\"{\");\n if (openIndex === -1) {\n throw new Error(\"VCAP_APPLICATION JSON payload not found in cf env output\");\n }\n const closeIndex = findJsonObjectEnd(afterMarker, openIndex);\n if (closeIndex === -1) {\n throw new Error(\"Malformed VCAP_APPLICATION JSON in cf env output\");\n }\n return afterMarker.slice(openIndex, closeIndex + 1);\n}\n\nfunction requireApplicationField(\n application: Record<string, unknown>,\n field: string,\n): string {\n const value = application[field];\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new Error(`VCAP_APPLICATION.${field} must be a non-empty string`);\n }\n return value.trim();\n}\n\nexport function extractCfEnvApplicationIdentity(stdout: string): CfEnvApplicationIdentity {\n let application: unknown;\n try {\n application = JSON.parse(extractVcapApplicationJson(stdout));\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(\"VCAP_APPLICATION is not valid JSON\", { cause: error });\n }\n throw error;\n }\n if (!isRecord(application)) {throw new Error(\"VCAP_APPLICATION must be an object\");}\n return {\n appName: requireApplicationField(application, \"application_name\"),\n apiEndpoint: normalizeSapCfApiEndpoint(requireApplicationField(application, \"cf_api\")),\n orgName: requireApplicationField(application, \"organization_name\"),\n spaceName: requireApplicationField(application, \"space_name\"),\n };\n}\n\nfunction extractVcapSection(stdout: string): string {\n const start = stdout.indexOf(\"VCAP_SERVICES:\");\n if (start === -1) {throw new Error(\"VCAP_SERVICES section not found in cf env output\");}\n const after = stdout.slice(start + \"VCAP_SERVICES:\".length);\n const end = after.indexOf(\"VCAP_APPLICATION:\");\n const block = end === -1 ? after : after.slice(0, end);\n return block.trim();\n}\n\ninterface RawHanaCreds {\n host: string;\n port: string;\n user: string;\n password: string;\n schema: string;\n hdi_user: string;\n hdi_password: string;\n url: string;\n database_id: string;\n certificate: string;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction assertCreds(raw: unknown): RawHanaCreds {\n if (!isRecord(raw)) {throw new Error(\"HANA credentials must be an object\");}\n const req = [\"host\", \"port\", \"user\", \"password\", \"schema\", \"hdi_user\", \"hdi_password\", \"url\", \"database_id\", \"certificate\"];\n for (const k of req) {\n if (typeof raw[k] !== \"string\") {throw new Error(`Missing/invalid HANA credential field: \"${k}\"`);}\n }\n return raw as unknown as RawHanaCreds;\n}\n\nfunction mapCreds(raw: RawHanaCreds): HanaBinding[\"credentials\"] {\n return {\n host: raw.host,\n port: raw.port,\n user: raw.user,\n password: raw.password,\n schema: raw.schema,\n hdiUser: raw.hdi_user,\n hdiPassword: raw.hdi_password,\n ...(raw.url ? { url: raw.url } : {}),\n databaseId: raw.database_id,\n certificate: raw.certificate,\n };\n}\n\nexport function extractHanaBindingsFromCfEnv(stdout: string): readonly HanaBinding[] {\n const jsonText = extractVcapSection(stdout);\n let vcap: unknown;\n try {\n vcap = JSON.parse(jsonText);\n } catch {\n throw new Error(\"VCAP_SERVICES is not valid JSON\");\n }\n if (!isRecord(vcap)) {throw new Error(\"VCAP_SERVICES must be an object\");}\n\n const hana = vcap[\"hana\"];\n if (hana === undefined) {return [];}\n if (!Array.isArray(hana)) {throw new Error(\"VCAP_SERVICES.hana must be an array when present\");}\n\n return hana.map((b: unknown) => {\n if (!isRecord(b)) {throw new Error(\"HANA binding must be an object\");}\n const credsRaw = assertCreds(b[\"credentials\"]);\n const name = typeof b[\"name\"] === \"string\" ? b[\"name\"] : undefined;\n return {\n ...(name ? { name } : {}),\n credentials: mapCreds(credsRaw),\n } as HanaBinding;\n });\n}\n\n/**\n * Professional classification: only re-auth for real session/unauth problems.\n */\nexport function classifyCfError(stderr: string | undefined = \"\", stdout: string | undefined = \"\"): {\n readonly isAuthError: boolean;\n readonly reason: string;\n} {\n const text = `${stderr} ${stdout}`.toLowerCase();\n if (\n text.includes(\"not logged in\") ||\n text.includes(\"unauthorized\") ||\n text.includes(\"forbidden\") ||\n text.includes(\"credentials were rejected\") ||\n text.includes(\"authentication failed\") ||\n text.includes(\"cf auth\") ||\n text.includes(\"token\") ||\n text.includes(\"expired\") ||\n text.includes(\"session\")\n ) {\n return { isAuthError: true, reason: \"auth/session issue\" };\n }\n return { isAuthError: false, reason: \"\" };\n}\n","import {\n cfApi,\n cfAuth,\n cfEnv,\n cfEnvDirect,\n cfTargetSpace,\n classifyCfError,\n extractCfEnvApplicationIdentity,\n extractHanaBindingsFromCfEnv,\n formatCurrentCfAppSelector,\n getApiEndpointForRegion,\n normalizeSapCfApiEndpoint,\n readCurrentCfTarget,\n withCfSession,\n} from \"./cf.js\";\nimport type { CfEnvApplicationIdentity } from \"./cf.js\";\nimport { readSapCredentials } from \"./config.js\";\nimport type { SapCredentials } from \"./config.js\";\nimport { CfHanaError, CredentialsNotFoundError } from \"./errors.js\";\nimport type { CredentialSource, DbUserRole, HanaBinding, SelectorSource } from \"./types.js\";\n\nexport interface ResolveBindingsOptions {\n /** Deprecated compatibility flag. Binding discovery is always live. */\n readonly refresh?: boolean;\n readonly email?: string;\n readonly password?: string;\n}\n\nfunction errorMessageFromUnknown(error: unknown): string {\n return error instanceof Error ? error.message : \"Invalid or untrusted CF API endpoint.\";\n}\n\nexport interface ResolvedBindings {\n readonly selector: string;\n readonly appName: string;\n readonly bindings: readonly HanaBinding[];\n readonly source: CredentialSource;\n readonly selectorSource: SelectorSource;\n readonly regionConfirmed: boolean;\n readonly selectorCanBePinned: boolean;\n}\n\ninterface ResolvedAppTarget {\n readonly selector: string;\n readonly apiEndpoint: string;\n readonly orgName: string;\n readonly spaceName: string;\n readonly appName: string;\n readonly selectorSource: SelectorSource;\n readonly regionConfirmed: boolean;\n readonly selectorCanBePinned: boolean;\n}\n\nexport interface BindingSelector {\n readonly bindingName?: string;\n readonly bindingIndex?: number;\n}\n\nexport interface SelectedConnectionTarget {\n readonly host: string;\n readonly port: number;\n readonly user: string;\n readonly password: string;\n readonly schema: string;\n readonly certificate: string;\n readonly databaseId: string;\n}\n\nfunction parseExplicitTarget(selector: string): ResolvedAppTarget {\n const [regionKey, orgName, spaceName, appName, extra] = selector\n .split(\"/\")\n .map((part) => part.trim());\n if (extra !== undefined || !regionKey || !orgName || !spaceName || !appName) {\n throw new CfHanaError(\n \"CONFIG\",\n `Invalid selector \"${selector}\". Use region/org/space/app or a bare app name.`,\n );\n }\n const apiEndpoint = getApiEndpointForRegion(regionKey);\n if (apiEndpoint === undefined) {\n throw new CfHanaError(\n \"CONFIG\",\n `Unknown SAP CF region \"${regionKey}\". Verify the current SAP region list or use the current CF target.`,\n );\n }\n try {\n return {\n selector,\n apiEndpoint: normalizeSapCfApiEndpoint(apiEndpoint),\n orgName,\n spaceName,\n appName,\n selectorSource: \"explicit\",\n regionConfirmed: true,\n selectorCanBePinned: true,\n };\n } catch (error) {\n throw new CfHanaError(\"CONFIG\", errorMessageFromUnknown(error), { cause: error });\n }\n}\n\nasync function resolveTarget(selector: string): Promise<ResolvedAppTarget> {\n if (selector.includes(\"/\")) {\n return parseExplicitTarget(selector);\n }\n const current = await readCurrentCfTarget();\n if (current === undefined) {\n throw new CfHanaError(\n \"CONFIG\",\n \"No current CF target found. Run `cf target -o <org> -s <space>` or pass a full region/org/space/app selector.\",\n );\n }\n return {\n selector: formatCurrentCfAppSelector(current, selector),\n apiEndpoint: current.apiEndpoint,\n orgName: current.orgName,\n spaceName: current.spaceName,\n appName: selector,\n selectorSource: \"ambient\",\n regionConfirmed: current.regionKey !== undefined,\n selectorCanBePinned:\n current.regionKey !== undefined && getApiEndpointForRegion(current.regionKey) !== undefined,\n };\n}\n\nfunction commandErrorText(error: unknown): string {\n if (typeof error !== \"object\" || error === null) {\n return \"\";\n }\n if (\"stderr\" in error && typeof error.stderr === \"string\" && error.stderr.length > 0) {\n return error.stderr;\n }\n return \"message\" in error && typeof error.message === \"string\" ? error.message : \"\";\n}\n\nfunction isSameTarget(\n target: ResolvedAppTarget,\n current: Awaited<ReturnType<typeof readCurrentCfTarget>>,\n): boolean {\n return (\n current?.apiEndpoint === target.apiEndpoint &&\n current.orgName === target.orgName &&\n current.spaceName === target.spaceName\n );\n}\n\nasync function assertAmbientTargetUnchanged(target: ResolvedAppTarget): Promise<void> {\n const current = await readCurrentCfTarget();\n if (!isSameTarget(target, current)) {\n throw new CfHanaError(\n \"CONFIG\",\n \"CF target changed during binding discovery; no database connection was opened. Retry or use an explicit region/org/space/app selector.\",\n );\n }\n}\n\nfunction readCfEnvApplicationIdentity(stdout: string): CfEnvApplicationIdentity {\n try {\n return extractCfEnvApplicationIdentity(stdout);\n } catch (error) {\n throw new CfHanaError(\n \"CONFIG\",\n \"Could not verify cf env application identity for the ambient target; no database connection was opened. \" +\n \"Retry or use an explicit region/org/space/app selector.\",\n { cause: error },\n );\n }\n}\n\nfunction assertCfEnvApplicationMatchesTarget(\n target: ResolvedAppTarget,\n application: CfEnvApplicationIdentity,\n): void {\n const matches =\n application.apiEndpoint === target.apiEndpoint &&\n application.orgName === target.orgName &&\n application.spaceName === target.spaceName &&\n application.appName === target.appName;\n if (matches) {return;}\n throw new CfHanaError(\n \"CONFIG\",\n \"CF env application identity did not match the resolved ambient target; no database connection was opened. \" +\n \"Retry or use an explicit region/org/space/app selector.\",\n );\n}\n\nasync function readIsolatedBindings(\n target: ResolvedAppTarget,\n sap: SapCredentials,\n): Promise<readonly HanaBinding[]> {\n return await withCfSession(async (ctx) => {\n await cfApi(target.apiEndpoint, ctx);\n await cfAuth(sap.email, sap.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n return extractHanaBindingsFromCfEnv(await cfEnv(target.appName, ctx));\n });\n}\n\nasync function readBareBindings(\n target: ResolvedAppTarget,\n options: ResolveBindingsOptions,\n): Promise<readonly HanaBinding[]> {\n let stdout: string;\n try {\n stdout = await cfEnvDirect(target.appName);\n } catch (directError) {\n const classified = classifyCfError(commandErrorText(directError));\n if (!classified.isAuthError) {\n throw new CfHanaError(\n \"CONFIG\",\n `Failed to get HANA bindings for bare app \"${target.appName}\" using current target (org=${target.orgName}, space=${target.spaceName}). ` +\n `Verify with \"cf target\" and \"cf env ${target.appName}\".`,\n { cause: directError },\n );\n }\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (sap === undefined) {\n throw new CredentialsNotFoundError(\n `Current CF session problem for bare app \"${target.appName}\" (${classified.reason}).\\n` +\n `Run \"cf login\" + \"cf target\", or provide SAP_EMAIL + SAP_PASSWORD.`,\n { cause: directError },\n );\n }\n return await readIsolatedBindings(target, sap);\n }\n const application = readCfEnvApplicationIdentity(stdout);\n await assertAmbientTargetUnchanged(target);\n assertCfEnvApplicationMatchesTarget(target, application);\n return extractHanaBindingsFromCfEnv(stdout);\n}\n\n/** Resolve every HANA binding for a pinned selector or the current CF target. */\nexport async function resolveAppBindings(\n rawSelector: string,\n options: ResolveBindingsOptions,\n): Promise<ResolvedBindings> {\n const selector = rawSelector.trim();\n if (selector.length === 0) {\n throw new CfHanaError(\"CONFIG\", \"App selector is required\");\n }\n const target = await resolveTarget(selector);\n const bindings =\n target.selectorSource === \"ambient\"\n ? await readBareBindings(target, options)\n : await readExplicitBindings(target, options);\n if (bindings.length === 0) {\n throw new CredentialsNotFoundError(`App \"${target.selector}\" has no HANA service binding.`);\n }\n return {\n selector: target.selector,\n appName: target.appName,\n bindings,\n source: \"live\",\n selectorSource: target.selectorSource,\n regionConfirmed: target.regionConfirmed,\n selectorCanBePinned: target.selectorCanBePinned,\n };\n}\n\nasync function readExplicitBindings(\n target: ResolvedAppTarget,\n options: ResolveBindingsOptions,\n): Promise<readonly HanaBinding[]> {\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (sap === undefined) {\n throw new CredentialsNotFoundError(\n `SAP_EMAIL and SAP_PASSWORD are required to fetch HANA bindings for explicit selector \"${target.selector}\".`,\n );\n }\n return await readIsolatedBindings(target, sap);\n}\n\n/** Pick a single HANA binding from an app's bindings. */\nexport function selectBinding(\n bindings: readonly HanaBinding[],\n selector: BindingSelector,\n): HanaBinding {\n if (selector.bindingName !== undefined) {\n const match = bindings.find((binding) => binding.name === selector.bindingName);\n if (match === undefined) {\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `No HANA binding named \"${selector.bindingName}\"`,\n );\n }\n return match;\n }\n\n if (selector.bindingIndex !== undefined) {\n const match = bindings[selector.bindingIndex];\n if (match === undefined) {\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `No HANA binding at index ${String(selector.bindingIndex)}`,\n );\n }\n return match;\n }\n\n const first = bindings[0];\n if (first === undefined) {\n throw new CredentialsNotFoundError(\"No HANA bindings are available for this app\");\n }\n if (bindings.length > 1) {\n const labels = bindings\n .map((binding, index) => binding.name ?? `#${String(index)}`)\n .join(\", \");\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `App has multiple HANA bindings (${labels}); ` +\n `choose one with bindingName or bindingIndex`,\n );\n }\n return first;\n}\n\n/** Map a HANA binding to concrete connection parameters for the chosen role. */\nexport function toConnectionTarget(\n binding: HanaBinding,\n role: DbUserRole,\n): SelectedConnectionTarget {\n const credentials = binding.credentials;\n const port = Number.parseInt(credentials.port, 10);\n if (!Number.isInteger(port) || port <= 0) {\n throw new CfHanaError(\"CONFIG\", `Invalid HANA port in binding: \"${credentials.port}\"`);\n }\n return {\n host: credentials.host,\n port,\n user: role === \"hdi\" ? credentials.hdiUser : credentials.user,\n password: role === \"hdi\" ? credentials.hdiPassword : credentials.password,\n schema: credentials.schema,\n certificate: credentials.certificate,\n databaseId: credentials.databaseId ?? \"\",\n };\n}\n","import { appendFile } from \"node:fs/promises\";\n\nimport { envName, readEnv } from \"../config.js\";\nimport { QueryError } from \"../errors.js\";\nimport { classifyStatement } from \"../statements.js\";\nimport type { SqlParam, StatementKind } from \"../types.js\";\n\nimport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\nlet catalogFailureInjected = false;\n\n/**\n * Deterministic in-memory driver used by hermetic end-to-end tests and offline\n * smoke checks. Selected via `CF_HANA_DRIVER=fake`. It never opens a socket.\n */\ninterface FakeCatalogObjectRow extends Record<string, SqlParam> {\n readonly SCHEMA_NAME: string;\n readonly OBJECT_NAME: string;\n readonly OBJECT_TYPE: \"TABLE\" | \"VIEW\";\n}\n\nfunction catalogObjects(): readonly FakeCatalogObjectRow[] {\n return [\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"EXISTING_TABLE\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"MISSING_TABLE_FIXED\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"MISSING_TABLE_VIEW\", OBJECT_TYPE: \"VIEW\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"STATUS_ITEMS\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"CORE_AUTH_SCOPE\", OBJECT_TYPE: \"TABLE\" },\n ];\n}\n\nfunction tableColumns(): readonly Record<string, SqlParam>[] {\n return [\n { COLUMN_NAME: \"ID\", DATA_TYPE_NAME: \"INTEGER\", LENGTH: null, SCALE: null, IS_NULLABLE: \"FALSE\", POSITION: 1 },\n { COLUMN_NAME: \"IS_ACTIVE\", DATA_TYPE_NAME: \"BOOLEAN\", LENGTH: null, SCALE: null, IS_NULLABLE: \"TRUE\", POSITION: 2 },\n { COLUMN_NAME: \"SCOPE_NAME\", DATA_TYPE_NAME: \"NVARCHAR\", LENGTH: 255, SCALE: null, IS_NULLABLE: \"TRUE\", POSITION: 3 },\n ];\n}\n\nfunction throwForcedFailure(kind: StatementKind): void {\n const forcedFailure = readEnv(envName(\"FAKE_FAIL_STATEMENT\"))?.toLowerCase();\n if (forcedFailure === kind) {\n throw new Error(`fake driver forced ${kind.toUpperCase()} failure`);\n }\n}\n\nfunction throwEarlyFixtureError(upperSql: string): void {\n if (upperSql.includes(\"PRIVILEGE_ERROR_CODE\")) {\n throw new QueryError(\"insufficient privilege: not authorized\", { databaseCode: 258 });\n }\n if (upperSql.includes(\"PRIVILEGE_ERROR_MESSAGE\")) {\n throw new QueryError(\"insufficient privilege: grant is missing\");\n }\n if (upperSql.includes(\"NON_PRIVILEGE_ERROR\")) {\n throw new QueryError(\"fake unrelated query failure\", { databaseCode: 999 });\n }\n if (\n readEnv(envName(\"FAKE_PRIVILEGE_CATALOG\")) === \"1\" &&\n (upperSql.includes(\"SYS.TABLES\") || upperSql.includes(\"SYS.TABLE_COLUMNS\"))\n ) {\n throw new QueryError(\"insufficient privilege: catalog access denied\", { databaseCode: 258 });\n }\n}\n\nfunction catalogObjectsResult(): DriverExecResult {\n return {\n rows: catalogObjects(),\n columns: [\n { name: \"SCHEMA_NAME\", typeName: \"NVARCHAR\" },\n { name: \"OBJECT_NAME\", typeName: \"NVARCHAR\" },\n { name: \"OBJECT_TYPE\", typeName: \"NVARCHAR\" },\n ],\n affectedRows: 0,\n };\n}\n\nfunction tablesResult(): DriverExecResult {\n return {\n rows: [\n { SCHEMA_NAME: \"APP_SCHEMA\", TABLE_NAME: \"EXISTING_TABLE\", TABLE_TYPE: \"COLUMN TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", TABLE_NAME: \"STATUS_ITEMS\", TABLE_TYPE: \"ROW TABLE\" },\n ],\n columns: [\n { name: \"SCHEMA_NAME\", typeName: \"NVARCHAR\" },\n { name: \"TABLE_NAME\", typeName: \"NVARCHAR\" },\n { name: \"TABLE_TYPE\", typeName: \"NVARCHAR\" },\n ],\n affectedRows: 0,\n };\n}\n\nfunction tableColumnsResult(): DriverExecResult {\n return {\n rows: tableColumns(),\n columns: [\n { name: \"COLUMN_NAME\", typeName: \"NVARCHAR\" },\n { name: \"DATA_TYPE_NAME\", typeName: \"NVARCHAR\" },\n { name: \"LENGTH\", typeName: \"INTEGER\" },\n { name: \"SCALE\", typeName: \"INTEGER\" },\n { name: \"IS_NULLABLE\", typeName: \"NVARCHAR\" },\n { name: \"POSITION\", typeName: \"INTEGER\" },\n ],\n affectedRows: 0,\n };\n}\n\nfunction matchCatalogFixture(upperSql: string): DriverExecResult | undefined {\n if (upperSql.includes(\"SYS.TABLES\") && upperSql.includes(\"SYS.VIEWS\")) {\n if (readEnv(envName(\"FAKE_FAIL_CATALOG_ONCE\")) === \"1\" && !catalogFailureInjected) {\n catalogFailureInjected = true;\n throw new QueryError(\"fake transient catalog metadata failure\");\n }\n return catalogObjectsResult();\n }\n if (upperSql.includes(\"SYS.TABLES\")) {\n return tablesResult();\n }\n if (upperSql.includes(\"SYS.TABLE_COLUMNS\")) {\n return tableColumnsResult();\n }\n return void 0;\n}\n\nfunction throwLateFixtureError(upperSql: string): void {\n if (upperSql.includes(\"MISSING_TABLE\") || upperSql.includes(\"MISSING_TABLES\")) {\n throw new QueryError(\"invalid table name: MISSING_TABLE\", { sqlState: \"42S02\" });\n }\n if (upperSql.includes(\"ISACTIVE\")) {\n throw new QueryError(\"invalid column name: ISACTIVE: line 1 col 8 (at pos 7)\", { databaseCode: 260 });\n }\n if (upperSql.includes(\"LOB_ORDER_ERROR\")) {\n throw new QueryError(\"inconsistent datatype: LOB type is not allowed in ORDER BY clause\", { databaseCode: 266 });\n }\n if (upperSql.includes(\"LOB_GROUP_ERROR\")) {\n throw new QueryError(\"inconsistent datatype: LOB type is not allowed in GROUP BY clause\", { databaseCode: 274 });\n }\n}\n\nfunction lobFixtureResult(): DriverExecResult {\n return {\n rows: [\n {\n LOG_CONTENT: Buffer.from(\"Example log entry\", \"utf8\"),\n CLOB_CONTENT: Buffer.from(\"Clob log entry\", \"utf8\"),\n PAYLOAD: Buffer.from([0, 1, 2, 255]),\n },\n ],\n columns: [\n { name: \"LOG_CONTENT\", typeName: \"NCLOB\" },\n { name: \"CLOB_CONTENT\", typeName: \"CLOB\" },\n { name: \"PAYLOAD\", typeName: \"BLOB\" },\n ],\n affectedRows: 0,\n };\n}\n\nfunction matchDataFixture(upperSql: string): DriverExecResult | undefined {\n if (upperSql.includes(\"LOB_FIXTURE\")) {\n return lobFixtureResult();\n }\n if (upperSql.includes(\"SINGLE_COLUMN_FIXTURE\")) {\n return {\n rows: [{ VALUE: \"alpha\" }, { VALUE: \"beta\" }],\n columns: [{ name: \"VALUE\", typeName: \"NVARCHAR\" }],\n affectedRows: 0,\n };\n }\n if (upperSql.includes(\"DUMMY\")) {\n return {\n rows: [{ \"1\": 1 }],\n columns: [{ name: \"1\", typeName: \"INTEGER\" }],\n affectedRows: 0,\n };\n }\n return void 0;\n}\n\nfunction defaultResult(kind: StatementKind): DriverExecResult {\n if (kind === \"select\") {\n return {\n rows: [\n { ID: 1, NAME: \"sample-row\" },\n { ID: 2, NAME: \"second-row\" },\n ],\n columns: [\n { name: \"ID\", typeName: \"INTEGER\" },\n { name: \"NAME\", typeName: \"NVARCHAR\" },\n ],\n affectedRows: 0,\n };\n }\n if (kind === \"dml\") {\n return { rows: [], columns: [], affectedRows: 1 };\n }\n return { rows: [], columns: [], affectedRows: 0 };\n}\n\nfunction fakeExec(sql: string): DriverExecResult {\n const kind = classifyStatement(sql);\n throwForcedFailure(kind);\n const upperSql = sql.toUpperCase();\n throwEarlyFixtureError(upperSql);\n const catalogFixture = matchCatalogFixture(upperSql);\n if (catalogFixture !== undefined) {\n return catalogFixture;\n }\n throwLateFixtureError(upperSql);\n return matchDataFixture(upperSql) ?? defaultResult(kind);\n}\n\n/** Opt-in fake-driver trace; parameter values stay out of test artifacts. */\nasync function traceFakeExec(sql: string, params: readonly SqlParam[]): Promise<void> {\n const tracePath = readEnv(envName(\"FAKE_TRACE_FILE\"));\n if (tracePath === undefined) {\n return;\n }\n const entry = { sql, paramCount: params.length };\n await appendFile(tracePath, `${JSON.stringify(entry)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n}\n\nclass FakeConnection implements DriverConnection {\n private closed = false;\n\n async exec(sql: string, params: readonly SqlParam[]): Promise<DriverExecResult> {\n await traceFakeExec(sql, params);\n return fakeExec(sql);\n }\n\n setAutoCommit(_enabled: boolean): Promise<void> {\n return Promise.resolve();\n }\n\n commit(): Promise<void> {\n return Promise.resolve();\n }\n\n rollback(): Promise<void> {\n return Promise.resolve();\n }\n\n close(): Promise<void> {\n this.closed = true;\n return Promise.resolve();\n }\n\n isClosed(): boolean {\n return this.closed;\n }\n}\n\n/** Build the deterministic test-only fake HANA driver. */\nexport function createFakeDriver(): HanaDriver {\n return {\n name: \"fake\",\n connect: (_params: DriverConnectParams): Promise<DriverConnection> =>\n Promise.resolve(new FakeConnection()),\n };\n}\n","import { createClient } from \"hdb\";\nimport type { HdbClient, HdbColumnMetadata, HdbStatement } from \"hdb\";\n\nimport { CfHanaError, QueryError, databaseCode } from \"../errors.js\";\nimport { quoteIdentifier } from \"../statements.js\";\nimport type { QueryResultColumn, SqlParam } from \"../types.js\";\n\nimport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\nconst TYPE_NAMES: Readonly<Record<number, string>> = {\n 0: \"NULL\",\n 1: \"TINYINT\",\n 2: \"SMALLINT\",\n 3: \"INTEGER\",\n 4: \"BIGINT\",\n 5: \"DECIMAL\",\n 6: \"REAL\",\n 7: \"DOUBLE\",\n 8: \"CHAR\",\n 9: \"VARCHAR\",\n 10: \"NCHAR\",\n 11: \"NVARCHAR\",\n 12: \"BINARY\",\n 13: \"VARBINARY\",\n 14: \"DATE\",\n 15: \"TIME\",\n 16: \"TIMESTAMP\",\n 25: \"CLOB\",\n 26: \"NCLOB\",\n 27: \"BLOB\",\n 28: \"BOOLEAN\",\n 29: \"STRING\",\n 30: \"NSTRING\",\n 47: \"DECIMAL\",\n 51: \"TEXT\",\n 52: \"SHORTTEXT\",\n 62: \"DECIMAL\",\n};\n\nfunction typeName(code: number): string {\n return TYPE_NAMES[code] ?? `TYPE_${String(code)}`;\n}\n\nfunction extractSqlState(error: Error): string | undefined {\n const value = (error as { readonly sqlState?: unknown }).sqlState;\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction toQueryError(error: Error): QueryError {\n const sqlState = extractSqlState(error);\n const code = databaseCode(error);\n return new QueryError(error.message, {\n cause: error,\n ...(sqlState === undefined ? {} : { sqlState }),\n ...(code === undefined ? {} : { databaseCode: code }),\n });\n}\n\nfunction toColumns(\n metadata: readonly HdbColumnMetadata[] | undefined,\n): readonly QueryResultColumn[] {\n if (metadata === undefined) {\n return [];\n }\n return metadata.map((column) => ({\n name: column.columnDisplayName ?? column.columnName ?? \"\",\n typeName: typeName(column.dataType),\n }));\n}\n\nfunction toExecResult(statement: HdbStatement, raw: unknown): DriverExecResult {\n if (typeof raw === \"number\") {\n return { rows: [], columns: [], affectedRows: raw };\n }\n if (Array.isArray(raw)) {\n return {\n rows: raw as readonly Record<string, SqlParam>[],\n columns: toColumns(statement.resultSetMetadata),\n affectedRows: 0,\n };\n }\n return { rows: [], columns: [], affectedRows: 0 };\n}\n\nclass HdbConnection implements DriverConnection {\n private closed = false;\n\n constructor(private readonly client: HdbClient) {}\n\n async exec(sql: string, params: readonly SqlParam[]): Promise<DriverExecResult> {\n const statement = await this.prepareStatement(sql);\n try {\n const raw = await this.executeStatement(statement, params);\n return toExecResult(statement, raw);\n } finally {\n dropStatementQuietly(statement);\n }\n }\n\n setAutoCommit(enabled: boolean): Promise<void> {\n this.client.setAutoCommit(enabled);\n return Promise.resolve();\n }\n\n async commit(): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n this.client.commit((error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n }\n\n async rollback(): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n this.client.rollback((error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return;\n }\n this.closed = true;\n await new Promise<void>((resolve) => {\n this.client.disconnect(() => {\n resolve();\n });\n });\n this.client.close();\n }\n\n isClosed(): boolean {\n return (\n this.closed ||\n this.client.readyState === \"closed\" ||\n this.client.readyState === \"disconnected\"\n );\n }\n\n private async prepareStatement(sql: string): Promise<HdbStatement> {\n return await new Promise<HdbStatement>((resolve, reject) => {\n this.client.prepare(sql, (error, statement) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve(statement);\n }\n });\n });\n }\n\n private async executeStatement(\n statement: HdbStatement,\n params: readonly SqlParam[],\n ): Promise<unknown> {\n return await new Promise<unknown>((resolve, reject) => {\n statement.exec([...params], (error, result) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve(result);\n }\n });\n });\n }\n}\n\nfunction dropStatementQuietly(statement: HdbStatement): void {\n try {\n statement.drop();\n } catch {\n // Best-effort cleanup; preserve the query result or original query error.\n }\n}\n\nfunction openClient(client: HdbClient, timeoutMs: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) {\n return;\n }\n settled = true;\n client.close();\n reject(\n new CfHanaError(\n \"TIMEOUT\",\n `HANA connection timed out after ${String(timeoutMs)}ms`,\n ),\n );\n }, timeoutMs);\n timer.unref();\n client.connect((error) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n if (error) {\n reject(\n new CfHanaError(\"CONNECTION\", `Failed to connect to HANA: ${error.message}`, {\n cause: error,\n }),\n );\n } else {\n resolve();\n }\n });\n });\n}\n\nasync function closeClientQuietly(client: HdbClient): Promise<void> {\n try {\n await new Promise<void>((resolve) => {\n client.disconnect(() => {\n resolve();\n });\n });\n } catch {\n // Best-effort cleanup after a partially opened connection.\n }\n try {\n client.close();\n } catch {\n // Best-effort cleanup after a partially opened connection.\n }\n}\n\nfunction setCurrentSchema(client: HdbClient, schema: string): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n client.exec(`SET SCHEMA ${quoteIdentifier(schema)}`, (error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n}\n\nasync function connectHdb(params: DriverConnectParams): Promise<DriverConnection> {\n const client = createClient({\n host: params.host,\n port: params.port,\n user: params.user,\n password: params.password,\n ca: params.certificate,\n useTLS: true,\n });\n await openClient(client, params.connectTimeoutMs);\n try {\n await setCurrentSchema(client, params.schema);\n } catch (error) {\n await closeClientQuietly(client);\n throw error;\n }\n return new HdbConnection(client);\n}\n\n/** Build the production HANA driver backed by the pure-JavaScript `hdb` library. */\nexport function createHdbDriver(): HanaDriver {\n return {\n name: \"hdb\",\n connect: connectHdb,\n };\n}\n","import { envName, readEnv } from \"../config.js\";\nimport { CfHanaError } from \"../errors.js\";\n\nimport { createFakeDriver } from \"./fake.js\";\nimport { createHdbDriver } from \"./hdb.js\";\nimport type { HanaDriver } from \"./types.js\";\n\nexport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\n/**\n * Create a HANA driver by name. Defaults to `hdb`; the `CF_HANA_DRIVER`\n * environment variable overrides the default when no name is passed.\n */\nexport function createDriver(name?: string): HanaDriver {\n const resolved = name ?? readEnv(envName(\"DRIVER\")) ?? \"hdb\";\n switch (resolved) {\n case \"hdb\":\n return createHdbDriver();\n case \"fake\":\n return createFakeDriver();\n default:\n throw new CfHanaError(\"CONFIG\", `Unknown HANA driver: ${resolved}`);\n }\n}\n","import { appendFile, mkdir, readdir, rm } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { DbUserRole, StatementKind } from \"./types.js\";\n\nconst SAPTOOLS_DIR_NAME = \".saptools\";\nconst CF_HANA_DIR_NAME = \"cf-hana\";\nconst HISTORIES_DIR_NAME = \"histories\";\nconst HISTORY_RETENTION_DAYS = 5;\nconst HISTORY_FILE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}\\.jsonl$/;\n\nexport type SqlHistoryOperation = \"query\" | \"execute\";\n\nexport interface SqlHistoryEntryInput {\n readonly version: string;\n readonly operation: SqlHistoryOperation;\n readonly selector: string;\n readonly appName: string;\n readonly schema: string;\n readonly role: DbUserRole;\n readonly statement: StatementKind;\n readonly sql: string;\n readonly paramCount: number;\n readonly rowCount: number;\n readonly truncated: boolean;\n readonly elapsedMs: number;\n}\n\nexport interface SqlHistoryEntry extends SqlHistoryEntryInput {\n readonly at: string;\n}\n\nexport interface SqlHistoryWriteOptions {\n readonly now?: Date;\n readonly saptoolsRoot?: string;\n}\n\nfunction defaultSaptoolsRoot(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nfunction padDatePart(value: number): string {\n return value.toString().padStart(2, \"0\");\n}\n\nfunction dateKey(date: Date): string {\n return [\n date.getFullYear().toString(),\n padDatePart(date.getMonth() + 1),\n padDatePart(date.getDate()),\n ].join(\"-\");\n}\n\nfunction retentionCutoffKey(now: Date): string {\n const cutoff = new Date(now);\n cutoff.setHours(0, 0, 0, 0);\n cutoff.setDate(cutoff.getDate() - HISTORY_RETENTION_DAYS);\n return dateKey(cutoff);\n}\n\nfunction resolveSaptoolsRoot(root: string | undefined): string {\n return root ?? defaultSaptoolsRoot();\n}\n\nexport function cfHanaHistoryDirectory(saptoolsRoot?: string): string {\n return join(resolveSaptoolsRoot(saptoolsRoot), CF_HANA_DIR_NAME, HISTORIES_DIR_NAME);\n}\n\nexport function sqlHistoryFilePath(now: Date = new Date(), saptoolsRoot?: string): string {\n return join(cfHanaHistoryDirectory(saptoolsRoot), `${dateKey(now)}.jsonl`);\n}\n\nasync function pruneSqlHistory(now: Date, saptoolsRoot?: string): Promise<void> {\n const historyDir = cfHanaHistoryDirectory(saptoolsRoot);\n let files: readonly string[];\n try {\n files = await readdir(historyDir);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n\n const cutoffKey = retentionCutoffKey(now);\n await Promise.all(\n files\n .filter((file) => HISTORY_FILE_PATTERN.test(file))\n .filter((file) => file.slice(0, 10) < cutoffKey)\n .map(async (file) => {\n await rm(join(historyDir, file), { force: true });\n }),\n );\n}\n\nexport async function appendSqlHistory(\n input: SqlHistoryEntryInput,\n options: SqlHistoryWriteOptions = {},\n): Promise<SqlHistoryEntry> {\n const now = options.now ?? new Date();\n const historyDir = cfHanaHistoryDirectory(options.saptoolsRoot);\n const entry: SqlHistoryEntry = {\n at: now.toISOString(),\n ...input,\n };\n\n await mkdir(historyDir, { recursive: true, mode: 0o700 });\n await appendFile(sqlHistoryFilePath(now, options.saptoolsRoot), `${JSON.stringify(entry)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n try {\n await pruneSqlHistory(now, options.saptoolsRoot);\n } catch {\n // Retention is best-effort; the SQL history entry was already recorded.\n }\n\n return entry;\n}\n","import { classifyStatement, firstKeyword } from \"./statements.js\";\nimport type { StatementKind } from \"./types.js\";\n\nconst DESTRUCTIVE_DDL_KEYWORDS = new Set([\"DROP\", \"TRUNCATE\", \"ALTER\"]);\nconst UNSCOPED_WRITE_KEYWORDS = new Set([\"UPDATE\", \"DELETE\"]);\n\nexport type GuardViolation = \"read-only\" | \"destructive\";\n\nexport interface GuardConfig {\n readonly readOnly: boolean;\n readonly allowDestructive: boolean;\n}\n\nexport interface GuardDecision {\n readonly allowed: boolean;\n readonly destructive: boolean;\n readonly violation: GuardViolation | undefined;\n readonly reason: string | undefined;\n}\n\nexport interface StatementInspection {\n readonly kind: StatementKind;\n readonly destructive: boolean;\n}\n\nexport interface AutoLimitResult {\n readonly sql: string;\n readonly applied: boolean;\n readonly requestedLimit?: number;\n}\n\nfunction skipQuotedText(sql: string, start: number): number {\n const quote = sql[start];\n let index = start + 1;\n while (index < sql.length) {\n if (sql[index] === quote) {\n if (sql[index + 1] === quote) {\n index += 2;\n continue;\n }\n index += 1;\n break;\n }\n index += 1;\n }\n return index;\n}\n\nfunction skipLineComment(sql: string, start: number): number {\n let index = start + 2;\n while (index < sql.length && sql[index] !== \"\\n\") {\n index += 1;\n }\n return index;\n}\n\nfunction skipBlockComment(sql: string, start: number): number {\n let index = start + 2;\n while (index < sql.length && !(sql[index] === \"*\" && sql[index + 1] === \"/\")) {\n index += 1;\n }\n return Math.min(index + 2, sql.length);\n}\n\nfunction maskIgnoredSqlText(sql: string): string {\n let masked = \"\";\n let index = 0;\n while (index < sql.length) {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n const end = skipQuotedText(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n const end = skipLineComment(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n const end = skipBlockComment(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n masked += char ?? \"\";\n index += 1;\n }\n return masked;\n}\n\nfunction hasTopLevelKeyword(sql: string, keyword: string): boolean {\n const masked = maskIgnoredSqlText(sql);\n let depth = 0;\n for (let index = 0; index < masked.length; index += 1) {\n const char = masked[index];\n if (char === \"(\") {\n depth += 1;\n continue;\n }\n if (char === \")\") {\n depth = Math.max(0, depth - 1);\n continue;\n }\n if (\n depth === 0 &&\n masked.slice(index, index + keyword.length).toUpperCase() === keyword &&\n !/[A-Za-z0-9_$#]/.test(masked.charAt(index - 1)) &&\n !/[A-Za-z0-9_$#]/.test(masked.charAt(index + keyword.length))\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction isUnconditionalMergeDelete(sql: string): boolean {\n return /\\bWHEN\\s+MATCHED\\s+THEN\\s+DELETE\\b/i.test(maskIgnoredSqlText(sql));\n}\n\nfunction isMalformedReplace(sql: string): boolean {\n return (\n !hasTopLevelKeyword(sql, \"VALUES\") &&\n !hasTopLevelKeyword(sql, \"SELECT\") &&\n !hasTopLevelKeyword(sql, \"WITH\")\n );\n}\n\nfunction trailingLineCommentIndex(sql: string): number | undefined {\n let index = 0;\n while (index < sql.length) {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n index = skipQuotedText(sql, index);\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n index = skipBlockComment(sql, index);\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n const lineEnd = sql.indexOf(\"\\n\", index + 2);\n if (lineEnd === -1 || sql.slice(lineEnd + 1).trim().length === 0) {\n return index;\n }\n index = lineEnd + 1;\n continue;\n }\n index += 1;\n }\n return undefined;\n}\n\nfunction appendLimit(sql: string, limit: number): string {\n const trimmed = sql.replace(/[\\s;]+$/, \"\");\n const commentIndex = trailingLineCommentIndex(trimmed);\n if (commentIndex === undefined) {\n return `${trimmed} LIMIT ${String(limit)}`;\n }\n const beforeComment = trimmed.slice(0, commentIndex).replace(/[\\s;]+$/, \"\");\n const comment = trimmed.slice(commentIndex);\n return `${beforeComment} LIMIT ${String(limit)} ${comment}`;\n}\n\n/** Inspect a statement's kind and whether it is destructive. */\nexport function inspectStatement(sql: string): StatementInspection {\n const kind = classifyStatement(sql);\n const keyword = firstKeyword(sql);\n if (kind === \"ddl\") {\n return { kind, destructive: DESTRUCTIVE_DDL_KEYWORDS.has(keyword) };\n }\n if (kind === \"dml\") {\n const destructive =\n (UNSCOPED_WRITE_KEYWORDS.has(keyword) && !hasTopLevelKeyword(sql, \"WHERE\")) ||\n (keyword === \"MERGE\" && isUnconditionalMergeDelete(sql)) ||\n (keyword === \"REPLACE\" && isMalformedReplace(sql));\n return {\n kind,\n destructive,\n };\n }\n return { kind, destructive: false };\n}\n\n/** Decide whether a statement may run under the given safety configuration. */\nexport function evaluateGuard(sql: string, config: GuardConfig): GuardDecision {\n const inspection = inspectStatement(sql);\n\n if (config.readOnly && inspection.kind !== \"select\") {\n return {\n allowed: false,\n destructive: inspection.destructive,\n violation: \"read-only\",\n reason:\n inspection.kind === \"unknown\"\n ? \"read-only mode only permits SELECT/WITH statements\"\n : `read-only mode blocks ${inspection.kind.toUpperCase()} statements`,\n };\n }\n\n if (inspection.destructive && !config.allowDestructive) {\n return {\n allowed: false,\n destructive: true,\n violation: \"destructive\",\n reason:\n \"destructive statement blocked (DROP/TRUNCATE/ALTER, unscoped UPDATE/DELETE, \" +\n \"or unconditional matched MERGE DELETE); \" +\n \"allow it explicitly to proceed\",\n };\n }\n\n return {\n allowed: true,\n destructive: inspection.destructive,\n violation: undefined,\n reason: undefined,\n };\n}\n\n/** Append a `LIMIT` clause to a bare SELECT that has no row cap of its own. */\nexport function applyAutoLimit(sql: string, limit: number | false): AutoLimitResult {\n if (limit === false || classifyStatement(sql) !== \"select\") {\n return { sql, applied: false };\n }\n\n const stripped = maskIgnoredSqlText(sql);\n if (/\\blimit\\b/i.test(stripped) || /\\btop\\s+\\d/i.test(stripped)) {\n return { sql, applied: false };\n }\n\n return {\n sql: appendLimit(sql, limit + 1),\n applied: true,\n requestedLimit: limit,\n };\n}\n","import type { DriverConnection, HanaDriver } from \"./driver/types.js\";\nimport { CfHanaError, DestructiveStatementError, ReadOnlyViolationError } from \"./errors.js\";\nimport { applyAutoLimit, evaluateGuard } from \"./safety.js\";\nimport { assertParamArity, classifyStatement } from \"./statements.js\";\nimport type {\n QueryOptions,\n QueryResult,\n QueryResultColumn,\n QueryRow,\n SqlParam,\n} from \"./types.js\";\n\nexport interface ConnectionConfig {\n readonly host: string;\n readonly port: number;\n readonly user: string;\n readonly password: string;\n readonly schema: string;\n readonly certificate: string;\n readonly connectTimeoutMs: number;\n readonly queryTimeoutMs: number;\n readonly readOnly: boolean;\n readonly allowDestructive: boolean;\n readonly autoLimit: number | false;\n}\n\ninterface RunOptions {\n readonly bypassSafety?: boolean;\n}\n\nfunction assertValidAutoLimit(value: number | false): void {\n if (\n value !== false &&\n (!Number.isSafeInteger(value) || value <= 0 || value >= Number.MAX_SAFE_INTEGER)\n ) {\n throw new CfHanaError(\"CONFIG\", \"autoLimit must be a positive safe integer\");\n }\n}\n\nfunction boundedRows(\n rows: readonly Record<string, SqlParam>[],\n requestedLimit: number | undefined,\n): {\n readonly rows: readonly Record<string, SqlParam>[];\n readonly truncated: boolean;\n} {\n if (requestedLimit === undefined) {\n return { rows, truncated: false };\n }\n return {\n rows: rows.slice(0, requestedLimit),\n truncated: rows.length > requestedLimit,\n };\n}\n\nfunction isBooleanColumn(column: QueryResultColumn): boolean {\n return column.typeName.trim().toUpperCase() === \"BOOLEAN\";\n}\n\nfunction normalizeBooleanCell(value: SqlParam): SqlParam {\n if (value === 0) {\n return false;\n }\n if (value === 1) {\n return true;\n }\n if (typeof value !== \"string\") {\n return value;\n }\n\n const normalized = value.trim().toLowerCase();\n if (normalized === \"0\") {\n return false;\n }\n if (normalized === \"1\") {\n return true;\n }\n if (normalized === \"false\") {\n return false;\n }\n if (normalized === \"true\") {\n return true;\n }\n return value;\n}\n\nfunction normalizeBooleanRow(\n row: Record<string, SqlParam>,\n columns: readonly QueryResultColumn[],\n): Record<string, SqlParam> {\n let normalizedRow: Record<string, SqlParam> | undefined;\n for (const column of columns) {\n const value = row[column.name];\n if (value === undefined) {\n continue;\n }\n const normalizedValue = normalizeBooleanCell(value);\n if (normalizedValue === value) {\n continue;\n }\n normalizedRow ??= { ...row };\n normalizedRow[column.name] = normalizedValue;\n }\n return normalizedRow ?? row;\n}\n\nfunction normalizeBooleanRows(\n rows: readonly Record<string, SqlParam>[],\n columns: readonly QueryResultColumn[],\n): readonly Record<string, SqlParam>[] {\n const booleanColumns = columns.filter(isBooleanColumn);\n if (booleanColumns.length === 0 || rows.length === 0) {\n return rows;\n }\n return rows.map((row) => normalizeBooleanRow(row, booleanColumns));\n}\n\nasync function withTimeout<T>(\n work: Promise<T>,\n timeoutMs: number,\n onTimeout: () => void,\n): Promise<T> {\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n onTimeout();\n reject(\n new CfHanaError(\"TIMEOUT\", `Statement timed out after ${String(timeoutMs)}ms`),\n );\n }, timeoutMs);\n timer.unref();\n });\n\n try {\n return await Promise.race([work, timeout]);\n } finally {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n }\n}\n\n/** A single HANA connection: applies the safety guard, auto-limit, and timeouts. */\nexport class Connection {\n private constructor(\n private readonly driverConnection: DriverConnection,\n private readonly config: ConnectionConfig,\n ) {}\n\n static async open(driver: HanaDriver, config: ConnectionConfig): Promise<Connection> {\n const driverConnection = await driver.connect({\n host: config.host,\n port: config.port,\n user: config.user,\n password: config.password,\n schema: config.schema,\n certificate: config.certificate,\n connectTimeoutMs: config.connectTimeoutMs,\n });\n return new Connection(driverConnection, config);\n }\n\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n const result = await this.run(sql, params ?? [], options ?? {});\n // The driver returns untyped rows; the caller asserts the row shape via TRow.\n return result as unknown as QueryResult<TRow>;\n }\n\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.run(sql, params ?? [], options ?? {});\n }\n\n assertAllowed(sql: string, options?: QueryOptions): void {\n this.evaluateSafety(sql, options ?? {});\n }\n\n async executeInternal(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.run(sql, params ?? [], options ?? {}, { bypassSafety: true });\n }\n\n async setAutoCommit(enabled: boolean): Promise<void> {\n await this.driverConnection.setAutoCommit(enabled);\n }\n\n async commit(): Promise<void> {\n await this.driverConnection.commit();\n }\n\n async rollback(): Promise<void> {\n await this.driverConnection.rollback();\n }\n\n async close(): Promise<void> {\n await this.driverConnection.close();\n }\n\n get isClosed(): boolean {\n return this.driverConnection.isClosed();\n }\n\n private async run(\n sql: string,\n params: readonly SqlParam[],\n options: QueryOptions,\n runOptions: RunOptions = {},\n ): Promise<QueryResult> {\n assertParamArity(sql, params);\n if (runOptions.bypassSafety !== true) {\n this.evaluateSafety(sql, options);\n }\n\n const kind = classifyStatement(sql);\n const autoLimit = options.autoLimit ?? this.config.autoLimit;\n assertValidAutoLimit(autoLimit);\n const limited =\n kind === \"select\" ? applyAutoLimit(sql, autoLimit) : { sql, applied: false };\n const timeoutMs = options.timeoutMs ?? this.config.queryTimeoutMs;\n\n const started = Date.now();\n const execResult = await withTimeout(\n this.driverConnection.exec(limited.sql, params),\n timeoutMs,\n () => {\n void this.closeQuietly();\n },\n );\n const elapsedMs = Date.now() - started;\n const normalizedRows = normalizeBooleanRows(execResult.rows, execResult.columns);\n const selected = boundedRows(normalizedRows, limited.requestedLimit);\n\n return {\n rows: selected.rows,\n columns: execResult.columns,\n rowCount: kind === \"select\" ? selected.rows.length : execResult.affectedRows,\n statement: kind,\n truncated: selected.truncated,\n elapsedMs,\n };\n }\n\n private async closeQuietly(): Promise<void> {\n try {\n await this.driverConnection.close();\n } catch {\n // Best-effort close after a timeout; the connection is already unusable.\n }\n }\n\n private evaluateSafety(sql: string, options: QueryOptions): void {\n const decision = evaluateGuard(sql, {\n readOnly: this.config.readOnly,\n allowDestructive: options.allowDestructive ?? this.config.allowDestructive,\n });\n if (decision.allowed) {\n return;\n }\n if (decision.violation === \"read-only\") {\n throw new ReadOnlyViolationError(\n decision.reason ?? \"read-only mode blocks this statement\",\n );\n }\n throw new DestructiveStatementError(\n decision.reason ?? \"destructive statement blocked\",\n );\n }\n}\n","import { DEFAULT_POOL_IDLE_MS, DEFAULT_POOL_MAX } from \"./config.js\";\nimport { Connection } from \"./connection.js\";\nimport type { ConnectionConfig } from \"./connection.js\";\nimport type { HanaDriver } from \"./driver/types.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport type { PoolOptions } from \"./types.js\";\n\ninterface IdleEntry {\n readonly connection: Connection;\n readonly since: number;\n}\n\ninterface Waiter {\n readonly resolve: (connection: Connection) => void;\n readonly reject: (error: unknown) => void;\n}\n\nasync function closeQuietly(connection: Connection): Promise<void> {\n try {\n await connection.close();\n } catch {\n // Best-effort close.\n }\n}\n\n/**\n * A process-local, in-memory pool of HANA connections. It holds no shared disk\n * state, so multiple pools (in this or other processes) are fully independent.\n */\nexport class ConnectionPool {\n private readonly idle: IdleEntry[] = [];\n private readonly busy = new Set<Connection>();\n private readonly waiters: Waiter[] = [];\n private readonly maxSize: number;\n private readonly idleTimeoutMs: number;\n private created = 0;\n private draining = false;\n\n constructor(\n private readonly driver: HanaDriver,\n private readonly config: ConnectionConfig,\n options?: PoolOptions,\n ) {\n this.maxSize = Math.max(1, options?.max ?? DEFAULT_POOL_MAX);\n this.idleTimeoutMs = options?.idleTimeoutMs ?? DEFAULT_POOL_IDLE_MS;\n }\n\n /** Total connections currently owned by the pool (idle + busy). */\n get size(): number {\n return this.created;\n }\n\n /** Connections currently idle and immediately reusable. */\n get available(): number {\n return this.idle.length;\n }\n\n /** Borrow a connection, opening or queueing as needed. */\n async acquire(): Promise<Connection> {\n if (this.draining) {\n throw new CfHanaError(\"POOL_CLOSED\", \"Connection pool is draining\");\n }\n\n const reused = this.takeIdleConnection();\n if (reused !== undefined) {\n this.busy.add(reused);\n return reused;\n }\n\n if (this.created < this.maxSize) {\n return await this.openBusyConnection();\n }\n\n return await new Promise<Connection>((resolve, reject) => {\n this.waiters.push({ resolve, reject });\n });\n }\n\n /** Return a borrowed connection to the pool. */\n release(connection: Connection): void {\n if (!this.busy.delete(connection)) {\n return;\n }\n\n if (connection.isClosed) {\n this.created -= 1;\n this.servePendingWaiters();\n return;\n }\n\n const waiter = this.waiters.shift();\n if (waiter !== undefined) {\n this.busy.add(connection);\n waiter.resolve(connection);\n return;\n }\n\n if (this.draining) {\n this.created -= 1;\n void closeQuietly(connection);\n return;\n }\n\n this.idle.push({ connection, since: Date.now() });\n }\n\n /** Run `work` with a borrowed connection, releasing it afterwards. */\n async withConnection<T>(work: (connection: Connection) => Promise<T>): Promise<T> {\n const connection = await this.acquire();\n try {\n return await work(connection);\n } finally {\n this.release(connection);\n }\n }\n\n /** Reject queued waiters and close idle connections. */\n async drain(): Promise<void> {\n this.draining = true;\n\n while (this.waiters.length > 0) {\n const waiter = this.waiters.shift();\n if (waiter !== undefined) {\n waiter.reject(new CfHanaError(\"POOL_CLOSED\", \"Connection pool was drained\"));\n }\n }\n\n const idleConnections = this.idle.splice(0).map((entry) => entry.connection);\n this.created -= idleConnections.length;\n await Promise.all(idleConnections.map((connection) => closeQuietly(connection)));\n }\n\n private takeIdleConnection(): Connection | undefined {\n for (;;) {\n const entry = this.idle.pop();\n if (entry === undefined) {\n return undefined;\n }\n if (entry.connection.isClosed) {\n this.created -= 1;\n continue;\n }\n if (this.idleTimeoutMs > 0 && Date.now() - entry.since > this.idleTimeoutMs) {\n this.created -= 1;\n void closeQuietly(entry.connection);\n continue;\n }\n return entry.connection;\n }\n }\n\n private async openBusyConnection(): Promise<Connection> {\n this.created += 1;\n let connection: Connection;\n try {\n connection = await Connection.open(this.driver, this.config);\n } catch (error) {\n this.created -= 1;\n throw error;\n }\n this.busy.add(connection);\n return connection;\n }\n\n private servePendingWaiters(): void {\n while (this.waiters.length > 0 && this.created < this.maxSize) {\n const waiter = this.waiters.shift();\n if (waiter === undefined) {\n return;\n }\n this.created += 1;\n void Connection.open(this.driver, this.config).then(\n (connection) => {\n this.busy.add(connection);\n waiter.resolve(connection);\n },\n (error: unknown) => {\n this.created -= 1;\n waiter.reject(error);\n this.servePendingWaiters();\n },\n );\n }\n }\n}\n","import type { Connection } from \"./connection.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport type { QueryOptions, QueryResult, QueryRow, SqlParam } from \"./types.js\";\n\n/** A HANA transaction bound to one connection with autocommit disabled. */\nexport class Transaction {\n private finished = false;\n\n constructor(private readonly connection: Connection) {}\n\n /** Whether the transaction has already been committed or rolled back. */\n get isFinished(): boolean {\n return this.finished;\n }\n\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n this.assertActive();\n return await this.connection.query<TRow>(sql, params, options);\n }\n\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n this.assertActive();\n return await this.connection.execute(sql, params, options);\n }\n\n async commit(): Promise<void> {\n this.assertActive();\n this.finished = true;\n await this.connection.commit();\n }\n\n async rollback(): Promise<void> {\n this.assertActive();\n this.finished = true;\n await this.connection.rollback();\n }\n\n private assertActive(): void {\n if (this.finished) {\n throw new CfHanaError(\n \"QUERY\",\n \"This transaction has already been committed or rolled back\",\n );\n }\n }\n}\n","import { buildWriteBackupPlan, writeSqlBackup } from \"./backup.js\";\nimport type { SqlBackupRecord } from \"./backup.js\";\nimport { buildCount, buildDelete, buildInsert, buildSelect, buildUpdate } from \"./builder.js\";\nimport { listCatalogObjects, listColumns, listSchemas, listTables } from \"./catalog.js\";\nimport {\n DEFAULT_AUTO_LIMIT,\n CLI_VERSION,\n DEFAULT_CONNECT_TIMEOUT_MS,\n DEFAULT_QUERY_TIMEOUT_MS,\n} from \"./config.js\";\nimport type { ConnectionConfig } from \"./connection.js\";\nimport { resolveAppBindings, selectBinding, toConnectionTarget } from \"./credentials.js\";\nimport { createDriver } from \"./driver/index.js\";\nimport { appendSqlHistory } from \"./history.js\";\nimport type { SqlHistoryOperation } from \"./history.js\";\nimport type { CatalogObjectInfo } from \"./metadata-cache.js\";\nimport { ConnectionPool } from \"./pool.js\";\nimport { Transaction } from \"./transaction.js\";\nimport type {\n ColumnInfo,\n ConnectOptions,\n DbUserRole,\n HanaBinding,\n HanaClientInfo,\n PoolOptions,\n QueryOptions,\n QueryResult,\n QueryRow,\n SelectSpec,\n SqlParam,\n TableInfo,\n} from \"./types.js\";\n\nlet explainStatementCounter = 0;\n\ninterface SelectedBindingInfo {\n readonly bindingName?: string;\n readonly bindingIndex: number;\n readonly availableBindingNames: readonly string[];\n}\n\nfunction nextExplainStatementName(): string {\n explainStatementCounter = (explainStatementCounter + 1) % Number.MAX_SAFE_INTEGER;\n return `cf_hana_${String(process.pid)}_${String(Date.now())}_${String(explainStatementCounter)}`;\n}\n\nfunction toPoolOptions(options: ConnectOptions): PoolOptions {\n if (options.pool === false) {\n return { max: 1 };\n }\n return options.pool ?? {};\n}\n\nfunction toSelectedBindingInfo(\n bindings: readonly HanaBinding[],\n selected: HanaBinding,\n): SelectedBindingInfo {\n const availableBindingNames = bindings.flatMap((binding) =>\n binding.name === undefined ? [] : [binding.name],\n );\n return {\n ...(selected.name === undefined ? {} : { bindingName: selected.name }),\n bindingIndex: bindings.indexOf(selected),\n availableBindingNames,\n };\n}\n\n/**\n * The high-level entry point: a pooled, reusable client for the HANA database\n * bound to a single Cloud Foundry app.\n */\nexport class HanaClient {\n constructor(\n private readonly pool: ConnectionPool,\n readonly info: HanaClientInfo,\n readonly databaseUser = \"\",\n ) {}\n\n /** Open a client for a `region/org/space/app` selector (or a bare app name). */\n static async connect(selector: string, options: ConnectOptions = {}): Promise<HanaClient> {\n const resolved = await resolveAppBindings(selector, options);\n const role: DbUserRole = options.role ?? \"runtime\";\n const binding = selectBinding(resolved.bindings, options);\n const bindingInfo = toSelectedBindingInfo(resolved.bindings, binding);\n const target = toConnectionTarget(binding, role);\n const driver = createDriver();\n\n const config: ConnectionConfig = {\n host: target.host,\n port: target.port,\n user: target.user,\n password: target.password,\n schema: target.schema,\n certificate: target.certificate,\n connectTimeoutMs: options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,\n queryTimeoutMs: options.queryTimeoutMs ?? DEFAULT_QUERY_TIMEOUT_MS,\n readOnly: options.readOnly ?? false,\n allowDestructive: options.allowDestructive ?? false,\n autoLimit: options.autoLimit ?? DEFAULT_AUTO_LIMIT,\n };\n const poolOptions = toPoolOptions(options);\n\n const info: HanaClientInfo = {\n selector: resolved.selector,\n appName: resolved.appName,\n host: target.host,\n schema: target.schema,\n role,\n driver: driver.name,\n credentialSource: resolved.source,\n selectorSource: resolved.selectorSource,\n regionConfirmed: resolved.regionConfirmed,\n selectorCanBePinned: resolved.selectorCanBePinned,\n ...bindingInfo,\n };\n return new HanaClient(new ConnectionPool(driver, config, poolOptions), info, target.user);\n }\n\n /** Run a SELECT (or any read) statement and return typed rows. */\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n const resolvedParams = params ?? [];\n const result = await this.runQuery<TRow>(sql, resolvedParams, options);\n await this.recordSqlHistory(\"query\", sql, resolvedParams, result);\n return result;\n }\n\n /** Run a DML/DDL statement and return its affected-row count. */\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n const resolvedParams = params ?? [];\n const result = await this.runExecute(sql, resolvedParams, options);\n await this.recordSqlHistory(\"execute\", sql, resolvedParams, result);\n return result;\n }\n\n /** Back up pre-image rows required by a supported write before the caller runs it. */\n async backupWriteStatement(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<SqlBackupRecord | undefined> {\n const resolvedParams = params ?? [];\n const plan = buildWriteBackupPlan(sql, resolvedParams);\n if (plan === undefined) {\n return undefined;\n }\n\n return await this.pool.withConnection(async (connection) => {\n connection.assertAllowed(plan.statementSql, options);\n const backupQueryOptions: QueryOptions = {\n autoLimit: false,\n ...(options?.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),\n };\n const result = await connection.query(plan.selectSql, plan.selectParams, backupQueryOptions);\n return await writeSqlBackup({\n operation: plan.operation,\n statementSql: plan.statementSql,\n result,\n selector: this.info.selector,\n });\n });\n }\n\n /** Run a typed `SELECT` built from a spec. */\n async selectFrom<TRow = QueryRow>(spec: SelectSpec): Promise<QueryResult<TRow>> {\n const built = buildSelect(spec);\n return await this.runQuery<TRow>(built.sql, built.params);\n }\n\n /** Count rows in a table, optionally filtered. */\n async count(spec: Pick<SelectSpec, \"schema\" | \"table\" | \"where\">): Promise<number> {\n const built = buildCount(spec);\n const result = await this.runQuery<{ COUNT: number }>(built.sql, built.params);\n return result.rows[0]?.COUNT ?? 0;\n }\n\n /** Insert a single row. */\n async insertInto(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildInsert(schema, table, values);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Update rows matching a non-empty `where` filter. */\n async update(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n where: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildUpdate(schema, table, values, where);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Delete rows matching a non-empty `where` filter. */\n async deleteFrom(\n schema: string,\n table: string,\n where: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildDelete(schema, table, where);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Run `work` inside a transaction, auto-committing on success. */\n async transaction<T>(work: (tx: Transaction) => Promise<T>): Promise<T> {\n return await this.pool.withConnection(async (connection) => {\n await connection.setAutoCommit(false);\n const tx = new Transaction(connection);\n try {\n const result = await work(tx);\n if (!tx.isFinished) {\n await tx.commit();\n }\n return result;\n } catch (error) {\n if (!tx.isFinished) {\n try {\n await tx.rollback();\n } catch {\n // Preserve the original error; ignore a rollback failure.\n }\n }\n throw error;\n } finally {\n await connection.setAutoCommit(true);\n }\n });\n }\n\n /** List every schema visible to the connected user. */\n async listSchemas(): Promise<readonly string[]> {\n return await this.pool.withConnection((connection) => listSchemas(connection));\n }\n\n /** List the tables in a schema. */\n async listTables(schema: string): Promise<readonly TableInfo[]> {\n return await this.pool.withConnection((connection) => listTables(connection, schema));\n }\n\n /** List table and view names in a schema for typo suggestions. */\n async listCatalogObjects(schema: string): Promise<readonly CatalogObjectInfo[]> {\n return await this.pool.withConnection((connection) => listCatalogObjects(connection, schema));\n }\n\n /** List the columns of a table. */\n async listColumns(schema: string, table: string): Promise<readonly ColumnInfo[]> {\n return await this.pool.withConnection((connection) =>\n listColumns(connection, schema, table),\n );\n }\n\n /** Return the HANA execution plan for a statement. */\n async explain(sql: string, params?: readonly SqlParam[]): Promise<QueryResult> {\n return await this.pool.withConnection(async (connection) => {\n connection.assertAllowed(sql);\n const statementName = nextExplainStatementName();\n await connection.executeInternal(\n `EXPLAIN PLAN SET STATEMENT_NAME = '${statementName}' FOR ${sql}`,\n params,\n );\n const cleanup = async (): Promise<void> => {\n await connection.executeInternal(\n \"DELETE FROM EXPLAIN_PLAN_TABLE WHERE STATEMENT_NAME = ?\",\n [statementName],\n );\n };\n let queryCompleted = false;\n try {\n const result = await connection.query(\n \"SELECT OPERATOR_NAME, TABLE_NAME, TABLE_TYPE, EXECUTION_ENGINE \" +\n \"FROM EXPLAIN_PLAN_TABLE WHERE STATEMENT_NAME = ? ORDER BY OPERATOR_ID\",\n [statementName],\n );\n queryCompleted = true;\n await cleanup();\n return result;\n } catch (error) {\n if (!queryCompleted) {\n try {\n await cleanup();\n } catch {\n // Preserve the original explain-plan read error.\n }\n }\n throw error;\n }\n });\n }\n\n /** Close every pooled connection. The client must not be used afterwards. */\n async close(): Promise<void> {\n await this.pool.drain();\n }\n\n private async runQuery<TRow = QueryRow>(\n sql: string,\n params: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n return await this.pool.withConnection((connection) =>\n connection.query<TRow>(sql, params, options),\n );\n }\n\n private async runExecute(\n sql: string,\n params: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.pool.withConnection((connection) =>\n connection.execute(sql, params, options),\n );\n }\n\n private async recordSqlHistory<TRow>(\n operation: SqlHistoryOperation,\n sql: string,\n params: readonly SqlParam[],\n result: QueryResult<TRow>,\n ): Promise<void> {\n try {\n await appendSqlHistory({\n version: CLI_VERSION,\n operation,\n selector: this.info.selector,\n appName: this.info.appName,\n schema: this.info.schema,\n role: this.info.role,\n statement: result.statement,\n sql,\n paramCount: params.length,\n rowCount: result.rowCount,\n truncated: result.truncated,\n elapsedMs: result.elapsedMs,\n });\n } catch {\n // History is diagnostic local state; never fail a successful SQL statement.\n }\n }\n}\n","import { HanaClient } from \"./client.js\";\nimport type {\n ConnectOptions,\n QueryOptions,\n QueryResult,\n QueryRow,\n SqlParam,\n} from \"./types.js\";\n\n/**\n * Open a reusable, pooled client for the HANA database bound to a Cloud Foundry\n * app, addressed by a `region/org/space/app` selector or a bare app name.\n */\nexport async function connect(\n selector: string,\n options?: ConnectOptions,\n): Promise<HanaClient> {\n return await HanaClient.connect(selector, options);\n}\n\n/**\n * Connect, run a single query, and close — the one-shot convenience for scripts.\n */\nexport async function query<TRow = QueryRow>(\n selector: string,\n sql: string,\n params?: readonly SqlParam[],\n options?: ConnectOptions & QueryOptions,\n): Promise<QueryResult<TRow>> {\n const client = await HanaClient.connect(selector, options);\n try {\n return await client.query<TRow>(sql, params, options);\n } finally {\n await client.close();\n }\n}\n\n/** Run `work` with a client that is closed automatically afterwards. */\nexport async function withConnection<T>(\n selector: string,\n work: (client: HanaClient) => Promise<T>,\n options?: ConnectOptions,\n): Promise<T> {\n const client = await HanaClient.connect(selector, options);\n try {\n return await work(client);\n } finally {\n await client.close();\n }\n}\n"],"mappings":"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","names":["typeName","next","join","appendFile","mkdir","rm","homedir","join","SAPTOOLS_DIR_NAME","CF_HANA_DIR_NAME","defaultSaptoolsRoot","skipQuotedText","skipLineComment","skipBlockComment"]}
1
+ {"version":3,"sources":["../src/backup.ts","../src/config.ts","../src/errors.ts","../src/lob.ts","../src/format.ts","../src/003-backup-sql-parser.ts","../src/statements.ts","../src/001-backup-planner.ts","../src/builder.ts","../src/catalog.ts","../src/cf.ts","../src/credentials.ts","../src/driver/fake.ts","../src/driver/hdb.ts","../src/driver/index.ts","../src/history.ts","../src/safety.ts","../src/tunnel/cache.ts","../src/tunnel/process.ts","../src/tunnel/candidates.ts","../src/tunnel/classifier.ts","../src/tunnel/fallback.ts","../src/connection.ts","../src/pool.ts","../src/transaction.ts","../src/client.ts","../src/api.ts"],"sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { WriteBackupOperation, WriteBackupPlan } from \"./001-backup-planner.js\";\nimport { MAX_RESULT_STORE_BYTES } from \"./config.js\";\nimport { BackupRequiredError } from \"./errors.js\";\nimport { formatCsv } from \"./format.js\";\nimport type { QueryResult } from \"./types.js\";\n\nexport { buildWriteBackupPlan } from \"./001-backup-planner.js\";\nexport type { WriteBackupOperation, WriteBackupPlan };\n\nconst SAPTOOLS_DIR_NAME = \".saptools\";\nconst CF_HANA_DIR_NAME = \"cf-hana\";\nconst BACKUPS_DIR_NAME = \"backups\";\n\nexport interface SqlBackupWriteInput {\n readonly operation: WriteBackupOperation;\n readonly statementSql: string;\n readonly result: QueryResult;\n readonly selector?: string;\n}\n\nexport interface SqlBackupWriteOptions {\n readonly now?: Date;\n readonly saptoolsRoot?: string;\n readonly maxBytes?: number;\n}\n\nexport interface SqlBackupRecord {\n readonly directory: string;\n readonly statementPath: string;\n readonly backupPath: string;\n readonly metadataPath: string;\n readonly rowCount: number;\n}\n\nfunction defaultSaptoolsRoot(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nfunction backupTimestamp(now: Date): string {\n return now.toISOString().replace(/:/g, \"\").replace(\".\", \"\");\n}\n\nfunction backupMonth(now: Date): string {\n const year = String(now.getUTCFullYear());\n const month = String(now.getUTCMonth() + 1).padStart(2, \"0\");\n return `${year}${month}`;\n}\n\nfunction sanitizePathPart(value: string | undefined): string {\n const trimmed = value?.trim() ?? \"\";\n const normalized = trimmed\n .replace(/[^A-Za-z0-9._-]+/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n return normalized.length > 0 ? normalized : \"unknown-target\";\n}\n\nfunction backupBaseName(input: SqlBackupWriteInput, now: Date): string {\n return [sanitizePathPart(input.selector), input.operation, backupTimestamp(now)].join(\"-\");\n}\n\nexport function cfHanaBackupRoot(saptoolsRoot?: string): string {\n return join(saptoolsRoot ?? defaultSaptoolsRoot(), CF_HANA_DIR_NAME, BACKUPS_DIR_NAME);\n}\n\nexport async function writeSqlBackup(\n input: SqlBackupWriteInput,\n options: SqlBackupWriteOptions = {},\n): Promise<SqlBackupRecord> {\n const now = options.now ?? new Date();\n const directory = join(cfHanaBackupRoot(options.saptoolsRoot), backupMonth(now));\n const baseName = backupBaseName(input, now);\n const statementPath = join(directory, `${baseName}.statement.sql`);\n const backupPath = join(directory, `${baseName}.sql`);\n const metadataPath = join(directory, `${baseName}.json`);\n const metadata = {\n selector: input.selector ?? null,\n operation: input.operation,\n statementPath,\n backupPath,\n rowCount: input.result.rowCount,\n createdAt: now.toISOString(),\n };\n const csv = formatCsv(input.result);\n if (Buffer.byteLength(csv) > (options.maxBytes ?? MAX_RESULT_STORE_BYTES)) {\n throw new BackupRequiredError(\n \"Write backup exceeds the storage limit; the write was refused\",\n );\n }\n\n await mkdir(directory, { recursive: true, mode: 0o700 });\n await Promise.all([\n writeFile(statementPath, `${input.statementSql}\\n`, { encoding: \"utf8\", mode: 0o600 }),\n writeFile(backupPath, csv, { encoding: \"utf8\", mode: 0o600 }),\n writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n }),\n ]);\n\n return {\n directory,\n statementPath,\n backupPath,\n metadataPath,\n rowCount: input.result.rowCount,\n };\n}\n","export const CLI_NAME = \"cf-hana\";\nexport const CLI_VERSION = \"0.5.0\";\nexport const ENV_PREFIX = \"CF_HANA\";\n\nexport const DEFAULT_QUERY_TIMEOUT_MS = 60_000;\nexport const DEFAULT_CONNECT_TIMEOUT_MS = 60_000;\nexport const DEFAULT_POOL_MAX = 4;\nexport const DEFAULT_POOL_IDLE_MS = 60_000;\nexport const DEFAULT_AUTO_LIMIT = 100;\nexport const DEFAULT_CELL_LIMIT = 128;\nexport const MAX_CELL_LIMIT = 10_000;\nexport const DEFAULT_RESULT_TTL_MINUTES = 10_080;\nexport const DEFAULT_RESULT_SEARCH_LIMIT = 20;\nconst DEFAULT_MAX_RESULT_STORE_BYTES = 256 * 1024 * 1024;\nexport const MAX_RESULT_STORE_BYTES = resolveMaxResultStoreBytes();\nexport const HANA_CLOUD_DEFAULT_PORT = 443;\n\nfunction resolvePositiveIntEnv(suffix: string, defaultValue: number): number {\n const raw = readEnv(envName(suffix));\n if (raw === undefined) {\n return defaultValue;\n }\n const parsed = Number(raw);\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : defaultValue;\n}\n\n/** Total wall-clock budget for the whole tunnel-fallback attempt, across every candidate. */\nexport const DEFAULT_TUNNEL_FALLBACK_BUDGET_MS = resolvePositiveIntEnv(\n \"TUNNEL_FALLBACK_BUDGET_MS\",\n 25_000,\n);\n/** Secondary per-candidate ceiling; the shared budget above still wins if smaller. */\nexport const DEFAULT_TUNNEL_CANDIDATE_TIMEOUT_MS = resolvePositiveIntEnv(\n \"TUNNEL_CANDIDATE_TIMEOUT_MS\",\n 15_000,\n);\n/** Additional jump-host apps tried beyond the target app itself. */\nexport const DEFAULT_TUNNEL_MAX_CANDIDATES = resolvePositiveIntEnv(\"TUNNEL_MAX_CANDIDATES\", 3);\n/** How long a spawned `cf ssh` forward is asked to stay open before it self-terminates. */\nexport const DEFAULT_TUNNEL_KEEPALIVE_SECONDS = resolvePositiveIntEnv(\n \"TUNNEL_KEEPALIVE_SECONDS\",\n 1200,\n);\n\nfunction resolveMaxResultStoreBytes(): number {\n // The fake driver can lower the cap so E2E tests exercise refusal without\n // allocating hundreds of MiB. Real HANA connections always use the hard cap.\n if (readEnv(envName(\"DRIVER\")) !== \"fake\") {\n return DEFAULT_MAX_RESULT_STORE_BYTES;\n }\n const raw = readEnv(envName(\"FAKE_MAX_STORE_BYTES\"));\n const parsed = raw === undefined ? Number.NaN : Number(raw);\n return Number.isSafeInteger(parsed) && parsed > 0\n ? parsed\n : DEFAULT_MAX_RESULT_STORE_BYTES;\n}\n\n/** Build a `CF_HANA_*` environment variable name from a suffix. */\nexport function envName(suffix: string): string {\n return `${ENV_PREFIX}_${suffix}`;\n}\n\n/** Read an environment variable, treating blank values as absent. */\nexport function readEnv(name: string): string | undefined {\n const value = process.env[name];\n if (value === undefined) {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length === 0 ? undefined : trimmed;\n}\n\nexport interface SapCredentials {\n readonly email: string;\n readonly password: string;\n}\n\nexport interface SapCredentialOverrides {\n readonly email?: string | undefined;\n readonly password?: string | undefined;\n}\n\n/**\n * Resolve SAP BTP credentials from explicit overrides, falling back to the\n * repo-wide `SAP_EMAIL` / `SAP_PASSWORD` environment variables. Returns\n * `undefined` when either half is missing.\n */\nexport function readSapCredentials(\n overrides?: SapCredentialOverrides,\n): SapCredentials | undefined {\n const email = overrides?.email ?? readEnv(\"SAP_EMAIL\");\n const password = overrides?.password ?? readEnv(\"SAP_PASSWORD\");\n if (email === undefined || password === undefined) {\n return undefined;\n }\n return { email, password };\n}\n","export type CfHanaErrorCode =\n | \"CONFIG\"\n | \"CREDENTIALS_NOT_FOUND\"\n | \"AMBIGUOUS_BINDING\"\n | \"CONNECTION\"\n | \"QUERY\"\n | \"BACKUP_REQUIRED\"\n | \"READ_ONLY_VIOLATION\"\n | \"DESTRUCTIVE_BLOCKED\"\n | \"TIMEOUT\"\n | \"POOL_CLOSED\";\n\nexport interface CfHanaErrorOptions {\n readonly cause?: unknown;\n}\n\nexport interface QueryErrorOptions extends CfHanaErrorOptions {\n readonly sqlState?: string;\n readonly databaseCode?: number;\n}\n\n/** Base error for every failure surfaced by `@saptools/cf-hana`. */\nexport class CfHanaError extends Error {\n readonly code: CfHanaErrorCode;\n\n constructor(code: CfHanaErrorCode, message: string, options?: CfHanaErrorOptions) {\n super(message, options);\n this.name = \"CfHanaError\";\n this.code = code;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** No HANA credentials could be resolved for the requested selector. */\nexport class CredentialsNotFoundError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"CREDENTIALS_NOT_FOUND\", message, options);\n this.name = \"CredentialsNotFoundError\";\n }\n}\n\n/** A SQL statement failed on the HANA server. */\nexport class QueryError extends CfHanaError {\n readonly sqlState: string | undefined;\n readonly databaseCode: number | undefined;\n\n constructor(message: string, options?: QueryErrorOptions) {\n super(\"QUERY\", message, options);\n this.name = \"QueryError\";\n this.sqlState = options?.sqlState;\n this.databaseCode = options?.databaseCode;\n }\n}\n\n/** A CLI write was refused because its required pre-image could not be preserved. */\nexport class BackupRequiredError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"BACKUP_REQUIRED\", message, options);\n this.name = \"BackupRequiredError\";\n }\n}\n\nfunction isDatabaseErrorShape(error: unknown): error is { readonly code?: unknown } {\n return typeof error === \"object\" && error !== null && \"code\" in error;\n}\n\nfunction safeDatabaseCode(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isSafeInteger(value)) {\n return value;\n }\n if (typeof value !== \"string\" || !/^\\d+$/.test(value)) {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) ? parsed : undefined;\n}\n\n/** Extract a numeric HANA database error code from wrapped query failures. */\nexport function databaseCode(error: unknown): number | undefined {\n if (error instanceof QueryError) {\n return error.databaseCode ?? databaseCode(error.cause);\n }\n if (isDatabaseErrorShape(error)) {\n return safeDatabaseCode(error.code);\n }\n return undefined;\n}\n\n/** A write/DDL statement was issued on a read-only client. */\nexport class ReadOnlyViolationError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"READ_ONLY_VIOLATION\", message, options);\n this.name = \"ReadOnlyViolationError\";\n }\n}\n\n/** A destructive statement was blocked because it was not explicitly allowed. */\nexport class DestructiveStatementError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"DESTRUCTIVE_BLOCKED\", message, options);\n this.name = \"DestructiveStatementError\";\n }\n}\n\n/** Narrow an unknown thrown value to a human-readable message. */\nexport function errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n return String(error);\n}\n","/** HANA column types whose Buffer values represent text rather than binary bytes. */\nconst TEXT_LOB_TYPES = new Set([\"CLOB\", \"NCLOB\"]);\n\nfunction normalizeTypeName(typeName: string | undefined): string {\n return typeName?.trim().toUpperCase() ?? \"\";\n}\n\nexport function isTextLobType(typeName: string | undefined): boolean {\n return TEXT_LOB_TYPES.has(normalizeTypeName(typeName));\n}\n","import { isTextLobType } from \"./lob.js\";\nimport { previewCell } from \"./result-preview.js\";\nimport type { OutputFormat, QueryResult, QueryResultColumn, SqlParam } from \"./types.js\";\n\ntype JsonCell = string | number | boolean | null;\n\nfunction cellText(value: SqlParam, nullText: string, column?: QueryResultColumn): string {\n if (value === null) {\n return nullText;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (Buffer.isBuffer(value)) {\n return isTextLobType(column?.typeName)\n ? value.toString(\"utf8\")\n : `0x${value.toString(\"hex\")}`;\n }\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n return typeof value === \"number\" ? value.toString() : value;\n}\n\nfunction serializeCell(value: SqlParam, column?: QueryResultColumn): JsonCell {\n if (value === null) {\n return null;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (Buffer.isBuffer(value)) {\n return isTextLobType(column?.typeName)\n ? value.toString(\"utf8\")\n : `0x${value.toString(\"hex\")}`;\n }\n return value;\n}\n\nfunction csvEscape(text: string): string {\n if (/[\",\\r\\n]/.test(text)) {\n return `\"${text.replace(/\"/g, '\"\"')}\"`;\n }\n return text;\n}\n\nexport interface CompactCsv {\n readonly text: string;\n readonly truncatedCells: number;\n}\n\n/** Render a result as an aligned ASCII table. */\nexport function formatTable(result: QueryResult): string {\n if (result.columns.length === 0) {\n return `(${String(result.rowCount)} row(s) affected)`;\n }\n\n const headers = result.columns.map((column) => column.name);\n const rows = result.rows.map((row) =>\n result.columns.map((column) => cellText(row[column.name] ?? null, \"NULL\", column)),\n );\n const widths = headers.map((header, index) => {\n const widest = rows.reduce(\n (max, cells) => Math.max(max, (cells[index] ?? \"\").length),\n header.length,\n );\n return widest;\n });\n\n const renderRow = (cells: readonly string[]): string =>\n cells.map((cell, index) => cell.padEnd(widths[index] ?? 0)).join(\" | \");\n const separator = widths.map((width) => \"-\".repeat(width)).join(\"-+-\");\n const body = rows.map((cells) => renderRow(cells));\n\n return [renderRow(headers), separator, ...body].join(\"\\n\");\n}\n\n/** Render a result's rows as pretty-printed JSON. */\nexport function formatJson(result: QueryResult): string {\n const rows = result.rows.map((row) => {\n const serialized: Record<string, JsonCell> = {};\n for (const [key, value] of Object.entries(row)) {\n const column = result.columns.find((item) => item.name === key);\n serialized[key] = serializeCell(value, column);\n }\n return serialized;\n });\n return JSON.stringify(rows, null, 2);\n}\n\nfunction formatJsonCompact(result: QueryResult, preferredColumn?: string): string {\n const singleColumn = result.columns.length === 1 ? result.columns[0]?.name : void 0;\n const columnName = preferredColumn ?? singleColumn;\n if (columnName === undefined) {\n return formatJson(result);\n }\n const column = result.columns.find((item) => item.name === columnName);\n const values = result.rows.map((row) => serializeCell(row[columnName] ?? null, column));\n return JSON.stringify(values, null, 2);\n}\n\n/** Render a result as RFC 4180 CSV. */\nexport function formatCsv(result: QueryResult): string {\n const headers = result.columns.map((column) => column.name);\n const lines = [headers.map((header) => csvEscape(header)).join(\",\")];\n for (const row of result.rows) {\n lines.push(\n result.columns\n .map((column) => csvEscape(cellText(row[column.name] ?? null, \"\", column)))\n .join(\",\"),\n );\n }\n return lines.join(\"\\r\\n\");\n}\n\n/** Render bounded CSV for CLI SELECT output without mutating the source result. */\nexport function formatCompactCsv(result: QueryResult, cellLimit: number): CompactCsv {\n const headers = result.columns.map((column) => column.name);\n const lines = [headers.map((header) => csvEscape(header)).join(\",\")];\n let truncatedCells = 0;\n for (const row of result.rows) {\n const cells = result.columns.map((column) => {\n const preview = previewCell(row[column.name] ?? null, cellLimit, column.typeName);\n if (preview.truncated) {\n truncatedCells += 1;\n }\n return csvEscape(preview.text);\n });\n lines.push(cells.join(\",\"));\n }\n return { text: lines.join(\"\\r\\n\"), truncatedCells };\n}\n\n/** Render a query result in the requested output format. */\nexport function formatResult(\n result: QueryResult,\n format: OutputFormat,\n compactColumn?: string,\n): string {\n switch (format) {\n case \"table\":\n return formatTable(result);\n case \"json\":\n return formatJson(result);\n case \"json-compact\":\n return formatJsonCompact(result, compactColumn);\n case \"csv\":\n return formatCsv(result);\n }\n}\n","export interface TopLevelToken {\n readonly keyword: string;\n readonly start: number;\n readonly end: number;\n}\n\nexport interface ParsedTarget {\n readonly sql: string;\n readonly reference: string;\n readonly end: number;\n}\n\nfunction isIdentifierChar(char: string | undefined): boolean {\n return char !== undefined && /[A-Za-z0-9_$#]/.test(char);\n}\n\nfunction skipQuotedText(sql: string, index: number): number {\n const quote = sql[index];\n let cursor = index + 1;\n while (cursor < sql.length) {\n if (sql[cursor] === quote) {\n if (sql[cursor + 1] === quote) {\n cursor += 2;\n continue;\n }\n return cursor + 1;\n }\n cursor += 1;\n }\n return cursor;\n}\n\nfunction skipLineComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && sql[cursor] !== \"\\n\") {\n cursor += 1;\n }\n return cursor;\n}\n\nfunction skipBlockComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && !(sql[cursor] === \"*\" && sql[cursor + 1] === \"/\")) {\n cursor += 1;\n }\n return Math.min(cursor + 2, sql.length);\n}\n\nfunction skipNonCode(sql: string, index: number): number | undefined {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n return skipQuotedText(sql, index);\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n return skipLineComment(sql, index);\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n return skipBlockComment(sql, index);\n }\n return undefined;\n}\n\nexport function skipTrivia(sql: string, start: number, end: number): number {\n let index = start;\n while (index < end) {\n if (/\\s/.test(sql.charAt(index))) {\n index += 1;\n continue;\n }\n if (sql[index] === \"-\" && sql[index + 1] === \"-\") {\n index = skipLineComment(sql, index);\n continue;\n }\n if (sql[index] === \"/\" && sql[index + 1] === \"*\") {\n index = skipBlockComment(sql, index);\n continue;\n }\n break;\n }\n return index;\n}\n\nexport function readIdentifierPart(\n sql: string,\n start: number,\n end: number,\n): { readonly sql: string; readonly end: number } | undefined {\n const index = skipTrivia(sql, start, end);\n if (sql[index] === '\"') {\n const next = skipQuotedText(sql, index);\n return next <= end && sql[next - 1] === '\"'\n ? { sql: sql.slice(index, next), end: next }\n : undefined;\n }\n if (!/[A-Za-z_#$]/.test(sql.charAt(index))) {\n return undefined;\n }\n let next = index + 1;\n while (next < end && /[A-Za-z0-9_#$]/.test(sql.charAt(next))) {\n next += 1;\n }\n return { sql: sql.slice(index, next), end: next };\n}\n\nexport function readQualifiedTarget(\n sql: string,\n start: number,\n end: number,\n): ParsedTarget | undefined {\n const first = readIdentifierPart(sql, start, end);\n if (first === undefined) {\n return undefined;\n }\n const parts = [first.sql];\n let cursor = first.end;\n while (parts.length < 3) {\n const dot = skipTrivia(sql, cursor, end);\n if (sql[dot] !== \".\") {\n break;\n }\n const part = readIdentifierPart(sql, dot + 1, end);\n if (part === undefined) {\n return undefined;\n }\n parts.push(part.sql);\n cursor = part.end;\n }\n return { sql: parts.join(\".\"), reference: parts.at(-1) ?? first.sql, end: cursor };\n}\n\nexport function topLevelTokens(sql: string): readonly TopLevelToken[] {\n const tokens: TopLevelToken[] = [];\n let index = 0;\n let depth = 0;\n while (index < sql.length) {\n const skipped = skipNonCode(sql, index);\n if (skipped !== undefined) {\n index = skipped;\n continue;\n }\n const char = sql.charAt(index);\n if (char === \"(\") {\n depth += 1;\n index += 1;\n continue;\n }\n if (char === \")\") {\n depth = Math.max(0, depth - 1);\n index += 1;\n continue;\n }\n if (!/[A-Za-z_#$]/.test(char)) {\n index += 1;\n continue;\n }\n let end = index + 1;\n while (end < sql.length && /[A-Za-z0-9_#$]/.test(sql.charAt(end))) {\n end += 1;\n }\n if (depth === 0) {\n tokens.push({ keyword: sql.slice(index, end).toUpperCase(), start: index, end });\n }\n index = end;\n }\n return tokens;\n}\n\nexport function findToken(\n tokens: readonly TopLevelToken[],\n keyword: string,\n start = 0,\n): number | undefined {\n for (let index = start; index < tokens.length; index += 1) {\n if (tokens[index]?.keyword === keyword) {\n return index;\n }\n }\n return undefined;\n}\n\nfunction keywordMatches(sql: string, index: number, keyword: string): boolean {\n const end = index + keyword.length;\n return (\n sql.slice(index, end).toUpperCase() === keyword &&\n !isIdentifierChar(sql[index - 1]) &&\n !isIdentifierChar(sql[end])\n );\n}\n\nexport function findTopLevelKeyword(\n sql: string,\n keyword: string,\n startIndex = 0,\n): number | undefined {\n let index = startIndex;\n let depth = 0;\n while (index < sql.length) {\n const skipped = skipNonCode(sql, index);\n if (skipped !== undefined) {\n index = skipped;\n continue;\n }\n const char = sql[index];\n if (char === \"(\") {\n depth += 1;\n } else if (char === \")\" && depth > 0) {\n depth -= 1;\n } else if (depth === 0 && keywordMatches(sql, index, keyword)) {\n return index;\n }\n index += 1;\n }\n return undefined;\n}\n\nexport function findTopLevelChar(\n sql: string,\n target: string,\n startIndex: number,\n endIndex: number,\n): number | undefined {\n let index = startIndex;\n let depth = 0;\n while (index < endIndex) {\n const skipped = skipNonCode(sql, index);\n if (skipped !== undefined) {\n index = skipped;\n continue;\n }\n const char = sql[index];\n if (char === target && depth === 0) {\n return index;\n }\n if (char === \"(\") {\n depth += 1;\n } else if (char === \")\" && depth > 0) {\n depth -= 1;\n }\n index += 1;\n }\n return undefined;\n}\n","import { QueryError } from \"./errors.js\";\nimport type { SqlParam, StatementKind } from \"./types.js\";\n\nconst SELECT_KEYWORDS = new Set([\"SELECT\", \"WITH\"]);\nconst DML_KEYWORDS = new Set([\"INSERT\", \"UPDATE\", \"DELETE\", \"MERGE\", \"UPSERT\", \"REPLACE\"]);\nconst DDL_KEYWORDS = new Set([\"CREATE\", \"DROP\", \"ALTER\", \"TRUNCATE\", \"RENAME\", \"COMMENT\"]);\n\n/** The leading SQL keyword, upper-cased, skipping comments and whitespace. */\nexport function firstKeyword(sql: string): string {\n let index = 0;\n while (index < sql.length) {\n const char = sql.charAt(index);\n if (char.trim().length === 0) {\n index += 1;\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n index += 2;\n while (index < sql.length && sql[index] !== \"\\n\") {\n index += 1;\n }\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n const commentEnd = sql.indexOf(\"*/\", index + 2);\n if (commentEnd === -1) {\n return \"\";\n }\n index = commentEnd + 2;\n continue;\n }\n break;\n }\n\n let keywordEnd = index;\n while (keywordEnd < sql.length) {\n const code = sql.charCodeAt(keywordEnd);\n const isUpperCase = code >= 65 && code <= 90;\n const isLowerCase = code >= 97 && code <= 122;\n if (!isUpperCase && !isLowerCase) {\n break;\n }\n keywordEnd += 1;\n }\n return sql.slice(index, keywordEnd).toUpperCase();\n}\n\n/** Classify a SQL statement by its leading keyword. */\nexport function classifyStatement(sql: string): StatementKind {\n const keyword = firstKeyword(sql);\n if (SELECT_KEYWORDS.has(keyword)) {\n return \"select\";\n }\n if (DML_KEYWORDS.has(keyword)) {\n return \"dml\";\n }\n if (DDL_KEYWORDS.has(keyword)) {\n return \"ddl\";\n }\n return \"unknown\";\n}\n\n/** Quote a SQL identifier (table/column name) for safe interpolation. */\nexport function quoteIdentifier(identifier: string): string {\n if (identifier.length === 0) {\n throw new QueryError(\"A SQL identifier must not be empty\");\n }\n if (identifier.includes(\"\\0\")) {\n throw new QueryError(\"A SQL identifier must not contain a NUL character\");\n }\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\n/** Build a `\"schema\".\"table\"` qualified, quoted name. */\nexport function qualifiedName(schema: string, table: string): string {\n return `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;\n}\n\n/** Count `?` placeholders, skipping string literals, quoted identifiers, and comments. */\nexport function countPlaceholders(sql: string): number {\n let count = 0;\n let index = 0;\n const length = sql.length;\n\n while (index < length) {\n const char = sql[index];\n\n if (char === \"'\" || char === '\"') {\n const quote = char;\n index += 1;\n while (index < length) {\n if (sql[index] === quote) {\n if (sql[index + 1] === quote) {\n index += 2;\n continue;\n }\n index += 1;\n break;\n }\n index += 1;\n }\n continue;\n }\n\n if (char === \"-\" && sql[index + 1] === \"-\") {\n index += 2;\n while (index < length && sql[index] !== \"\\n\") {\n index += 1;\n }\n continue;\n }\n\n if (char === \"/\" && sql[index + 1] === \"*\") {\n index += 2;\n while (index < length && !(sql[index] === \"*\" && sql[index + 1] === \"/\")) {\n index += 1;\n }\n index += 2;\n continue;\n }\n\n if (char === \"?\") {\n count += 1;\n }\n index += 1;\n }\n\n return count;\n}\n\n/** Throw when the number of `?` placeholders does not match the parameter count. */\nexport function assertParamArity(sql: string, params: readonly SqlParam[]): void {\n const expected = countPlaceholders(sql);\n if (expected !== params.length) {\n throw new QueryError(\n `SQL expects ${String(expected)} bound parameter(s) ` +\n `but received ${String(params.length)} value(s)`,\n );\n }\n}\n","import {\n findToken,\n findTopLevelChar,\n findTopLevelKeyword,\n readIdentifierPart,\n readQualifiedTarget,\n skipTrivia,\n topLevelTokens,\n} from \"./003-backup-sql-parser.js\";\nimport type { ParsedTarget, TopLevelToken } from \"./003-backup-sql-parser.js\";\nimport { BackupRequiredError, QueryError } from \"./errors.js\";\nimport { assertParamArity, countPlaceholders, firstKeyword } from \"./statements.js\";\nimport type { SqlParam } from \"./types.js\";\n\nexport type WriteBackupOperation = \"update\" | \"upsert\" | \"replace\" | \"merge\" | \"delete\";\n\nexport interface WriteBackupPlan {\n readonly operation: WriteBackupOperation;\n readonly statementSql: string;\n readonly selectSql: string;\n readonly selectParams: readonly SqlParam[];\n}\n\ninterface ParsedMerge {\n readonly tokens: readonly TopLevelToken[];\n readonly into: TopLevelToken;\n readonly using: TopLevelToken;\n readonly on: TopLevelToken;\n readonly target: ParsedTarget;\n readonly clauseIndexes: readonly number[];\n readonly matchedIndexes: readonly number[];\n readonly targetClause: string;\n readonly sourceClause: string;\n readonly onCondition: string;\n}\n\ninterface ParsedMatchedClause {\n readonly clauseStart: number;\n readonly matchedCondition: string;\n readonly conditionParams: readonly SqlParam[];\n}\n\ninterface MatchedActionTokens {\n readonly thenToken: TopLevelToken;\n readonly conditionToken: TopLevelToken | undefined;\n readonly clauseStart: number;\n}\n\ntype WriteKeyword = \"UPDATE\" | \"UPSERT\" | \"REPLACE\" | \"MERGE\" | \"DELETE\";\n\nconst WRITE_KEYWORDS = new Set<string>([\n \"UPDATE\",\n \"UPSERT\",\n \"REPLACE\",\n \"MERGE\",\n \"DELETE\",\n]);\nconst MERGE_MODIFY_ACTIONS = new Set<string>([\"UPDATE\", \"DELETE\"]);\n\nfunction trimStatementSql(sql: string): string {\n const trimmed = sql.trim();\n let end = trimmed.length;\n while (end > 0 && trimmed.charAt(end - 1) === \";\") {\n end -= 1;\n }\n return trimmed.slice(0, end).trim();\n}\n\nfunction isMergeClauseStart(tokens: readonly TopLevelToken[], index: number): boolean {\n if (tokens[index]?.keyword !== \"WHEN\") {\n return false;\n }\n return (\n tokens[index + 1]?.keyword === \"MATCHED\" ||\n (tokens[index + 1]?.keyword === \"NOT\" && tokens[index + 2]?.keyword === \"MATCHED\")\n );\n}\n\nfunction mergeClauseIndexes(\n tokens: readonly TopLevelToken[],\n start: number,\n): readonly number[] {\n const indexes: number[] = [];\n for (let index = start; index < tokens.length; index += 1) {\n if (isMergeClauseStart(tokens, index)) {\n indexes.push(index);\n }\n }\n return indexes;\n}\n\nfunction selectParamsAfterWhere(\n statementSql: string,\n whereIndex: number,\n params: readonly SqlParam[],\n): readonly SqlParam[] {\n return params.slice(countPlaceholders(statementSql.slice(0, whereIndex)));\n}\n\nfunction buildSelectPlan(\n operation: WriteBackupOperation,\n statementSql: string,\n targetSql: string,\n whereIndex: number | undefined,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const target = targetSql.trim();\n if (target.length === 0) {\n throw new QueryError(`${operation.toUpperCase()} backup requires a target table`);\n }\n if (whereIndex === undefined) {\n return { operation, statementSql, selectSql: `SELECT * FROM ${target}`, selectParams: [] };\n }\n\n const whereSql = statementSql.slice(whereIndex + \"WHERE\".length).trim();\n if (whereSql.length === 0) {\n throw new QueryError(`${operation.toUpperCase()} backup requires a non-empty WHERE clause`);\n }\n return {\n operation,\n statementSql,\n selectSql: `SELECT * FROM ${target} WHERE ${whereSql}`,\n selectParams: selectParamsAfterWhere(statementSql, whereIndex, params),\n };\n}\n\nfunction buildUpdateBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const updateIndex = findTopLevelKeyword(statementSql, \"UPDATE\");\n const setIndex =\n updateIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"SET\", updateIndex + \"UPDATE\".length);\n if (updateIndex === undefined || setIndex === undefined) {\n throw new QueryError(\"UPDATE backup requires UPDATE <target> SET syntax\");\n }\n\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", setIndex + \"SET\".length);\n return buildSelectPlan(\n \"update\",\n statementSql,\n statementSql.slice(updateIndex + \"UPDATE\".length, setIndex),\n whereIndex,\n params,\n );\n}\n\nfunction buildUpsertBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n keyword: \"UPSERT\" | \"REPLACE\",\n): WriteBackupPlan {\n const operation = keyword === \"UPSERT\" ? \"upsert\" : \"replace\";\n const keywordIndex = findTopLevelKeyword(statementSql, keyword);\n const target =\n keywordIndex === undefined\n ? undefined\n : readQualifiedTarget(statementSql, keywordIndex + keyword.length, statementSql.length);\n if (keywordIndex === undefined || target === undefined) {\n throw new BackupRequiredError(\n `${keyword} write refused: cannot derive a trustworthy backup target`,\n );\n }\n const valuesIndex = findTopLevelKeyword(statementSql, \"VALUES\", target.end);\n if (valuesIndex === undefined) {\n const selectIndex = findTopLevelKeyword(statementSql, \"SELECT\", target.end);\n const withIndex = findTopLevelKeyword(statementSql, \"WITH\", target.end);\n if (selectIndex === undefined && withIndex === undefined) {\n throw new BackupRequiredError(\n `${keyword} write refused: expected VALUES, WITH PRIMARY KEY, or a subquery`,\n );\n }\n return buildSelectPlan(operation, statementSql, target.sql, undefined, params);\n }\n\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", valuesIndex + \"VALUES\".length);\n return buildSelectPlan(operation, statementSql, target.sql, whereIndex, params);\n}\n\nfunction mergeTargetReference(\n statementSql: string,\n target: ParsedTarget,\n usingStart: number,\n): string | undefined {\n let suffix = statementSql.slice(target.end, usingStart).trim();\n if (suffix.length === 0) {\n return target.reference;\n }\n if (/^PARTITION\\b/i.test(suffix)) {\n const open = suffix.indexOf(\"(\");\n if (open === -1) {\n return undefined;\n }\n const close = findTopLevelChar(suffix, \")\", open + 1, suffix.length);\n if (close === undefined) {\n return undefined;\n }\n suffix = suffix.slice(close + 1).trim();\n if (suffix.length === 0) {\n return target.reference;\n }\n }\n suffix = suffix.replace(/^AS\\b/i, \"\").trim();\n const alias = readIdentifierPart(suffix, 0, suffix.length);\n if (alias === undefined || skipTrivia(suffix, alias.end, suffix.length) !== suffix.length) {\n return undefined;\n }\n return alias.sql;\n}\n\nfunction paramsInRange(\n sql: string,\n params: readonly SqlParam[],\n start: number,\n end: number,\n): readonly SqlParam[] {\n const offset = countPlaceholders(sql.slice(0, start));\n const length = countPlaceholders(sql.slice(start, end));\n return params.slice(offset, offset + length);\n}\n\nfunction wholeTargetPlan(\n operation: WriteBackupOperation,\n statementSql: string,\n target: ParsedTarget,\n): WriteBackupPlan {\n return buildSelectPlan(operation, statementSql, target.sql, undefined, []);\n}\n\nfunction readRequiredMergeToken(\n tokens: readonly TopLevelToken[],\n keyword: string,\n start: number,\n): { readonly index: number; readonly token: TopLevelToken } {\n const index = findToken(tokens, keyword, start);\n const token = index === undefined ? undefined : tokens[index];\n if (index === undefined || token === undefined) {\n throw new BackupRequiredError(\n \"MERGE write refused: cannot derive a trustworthy backup target\",\n );\n }\n return { index, token };\n}\n\nfunction parseMerge(statementSql: string): ParsedMerge {\n const tokens = topLevelTokens(statementSql);\n const into = readRequiredMergeToken(tokens, \"INTO\", 1);\n const using = readRequiredMergeToken(tokens, \"USING\", into.index + 1);\n const on = readRequiredMergeToken(tokens, \"ON\", using.index + 1);\n const target = readQualifiedTarget(statementSql, into.token.end, using.token.start);\n if (target === undefined) {\n throw new BackupRequiredError(\n \"MERGE write refused: cannot derive a trustworthy backup target\",\n );\n }\n const clauseIndexes = mergeClauseIndexes(tokens, on.index + 1);\n if (clauseIndexes.length === 0) {\n throw new BackupRequiredError(\"MERGE write refused: no supported WHEN clause was found\");\n }\n const firstClause = tokens[clauseIndexes[0] ?? 0];\n return {\n tokens,\n into: into.token,\n using: using.token,\n on: on.token,\n target,\n clauseIndexes,\n matchedIndexes: clauseIndexes.filter((index) => tokens[index + 1]?.keyword === \"MATCHED\"),\n targetClause: statementSql.slice(into.token.end, using.token.start).trim(),\n sourceClause: statementSql.slice(using.token.end, on.token.start).trim(),\n onCondition: statementSql.slice(on.token.end, firstClause?.start).trim(),\n };\n}\n\nfunction readMatchedActionTokens(\n tokens: readonly TopLevelToken[],\n matchedIndex: number,\n): MatchedActionTokens | undefined {\n const thenIndex = findToken(tokens, \"THEN\", matchedIndex + 2);\n if (thenIndex === undefined) {\n return undefined;\n }\n const thenToken = tokens[thenIndex];\n const actionToken = tokens[thenIndex + 1];\n const matchedToken = tokens[matchedIndex + 1];\n if (thenToken === undefined || actionToken === undefined || matchedToken === undefined) {\n return undefined;\n }\n if (!MERGE_MODIFY_ACTIONS.has(actionToken.keyword)) {\n return undefined;\n }\n const clauseToken = tokens[matchedIndex];\n return {\n thenToken,\n conditionToken: tokens[matchedIndex + 2],\n clauseStart: clauseToken === undefined ? 0 : clauseToken.start,\n };\n}\n\nfunction parseMatchedClause(\n statementSql: string,\n params: readonly SqlParam[],\n tokens: readonly TopLevelToken[],\n matchedIndex: number,\n): ParsedMatchedClause | undefined {\n const action = readMatchedActionTokens(tokens, matchedIndex);\n if (action?.conditionToken === undefined) {\n return undefined;\n }\n if (action.conditionToken.keyword === \"THEN\") {\n return { clauseStart: action.clauseStart, matchedCondition: \"\", conditionParams: [] };\n }\n if (action.conditionToken.keyword !== \"AND\") {\n return undefined;\n }\n return {\n clauseStart: action.clauseStart,\n matchedCondition: statementSql.slice(action.conditionToken.end, action.thenToken.start).trim(),\n conditionParams: paramsInRange(\n statementSql,\n params,\n action.conditionToken.end,\n action.thenToken.start,\n ),\n };\n}\n\nfunction buildExactMergePlan(\n statementSql: string,\n params: readonly SqlParam[],\n merge: ParsedMerge,\n matchedIndex: number,\n): WriteBackupPlan | undefined {\n const targetReference = mergeTargetReference(statementSql, merge.target, merge.using.start);\n const matchedClause = parseMatchedClause(statementSql, params, merge.tokens, matchedIndex);\n if (targetReference === undefined || matchedClause === undefined) {\n return undefined;\n }\n const sourceParams = paramsInRange(\n statementSql,\n params,\n merge.using.end,\n matchedClause.clauseStart,\n );\n const conditionSql = matchedClause.matchedCondition.length === 0\n ? \"\"\n : ` AND (${matchedClause.matchedCondition})`;\n return {\n operation: \"merge\",\n statementSql,\n selectSql:\n `SELECT ${targetReference}.* FROM ${merge.targetClause} ` +\n `WHERE EXISTS (SELECT 1 FROM ${merge.sourceClause} ` +\n `WHERE (${merge.onCondition})${conditionSql})`,\n selectParams: [...sourceParams, ...matchedClause.conditionParams],\n };\n}\n\nfunction buildMergeBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan | undefined {\n const merge = parseMerge(statementSql);\n if (merge.matchedIndexes.length === 0) {\n return undefined;\n }\n if (merge.matchedIndexes.length > 1) {\n return wholeTargetPlan(\"merge\", statementSql, merge.target);\n }\n if (merge.sourceClause.length === 0 || merge.onCondition.length === 0) {\n return wholeTargetPlan(\"merge\", statementSql, merge.target);\n }\n const matchedIndex = merge.matchedIndexes[0] ?? 0;\n return (\n buildExactMergePlan(statementSql, params, merge, matchedIndex) ??\n wholeTargetPlan(\"merge\", statementSql, merge.target)\n );\n}\n\nfunction buildDeleteBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const deleteIndex = findTopLevelKeyword(statementSql, \"DELETE\");\n const fromIndex =\n deleteIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"FROM\", deleteIndex + \"DELETE\".length);\n if (deleteIndex === undefined || fromIndex === undefined) {\n throw new QueryError(\"DELETE backup requires DELETE FROM <target> syntax\");\n }\n\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", fromIndex + \"FROM\".length);\n const targetEnd = whereIndex ?? statementSql.length;\n return buildSelectPlan(\n \"delete\",\n statementSql,\n statementSql.slice(fromIndex + \"FROM\".length, targetEnd),\n whereIndex,\n params,\n );\n}\n\nfunction isWriteKeyword(keyword: string): keyword is WriteKeyword {\n return WRITE_KEYWORDS.has(keyword);\n}\n\nfunction buildMergeWriteBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan | undefined {\n const secondKeyword = topLevelTokens(statementSql)[1]?.keyword;\n if (secondKeyword === \"DELTA\") {\n return undefined;\n }\n if (secondKeyword !== \"INTO\") {\n throw new BackupRequiredError(\"MERGE write refused: expected MERGE INTO syntax\");\n }\n return buildMergeBackupPlan(statementSql, params);\n}\n\nfunction dispatchWriteBackupPlan(\n keyword: WriteKeyword,\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan | undefined {\n switch (keyword) {\n case \"UPDATE\":\n return buildUpdateBackupPlan(statementSql, params);\n case \"UPSERT\":\n case \"REPLACE\":\n return buildUpsertBackupPlan(statementSql, params, keyword);\n case \"MERGE\":\n return buildMergeWriteBackupPlan(statementSql, params);\n case \"DELETE\":\n return buildDeleteBackupPlan(statementSql, params);\n }\n}\n\nexport function buildWriteBackupPlan(\n sql: string,\n params: readonly SqlParam[] = [],\n): WriteBackupPlan | undefined {\n const statementSql = trimStatementSql(sql);\n const keyword = firstKeyword(statementSql);\n if (!isWriteKeyword(keyword)) {\n return undefined;\n }\n assertParamArity(statementSql, params);\n return dispatchWriteBackupPlan(keyword, statementSql, params);\n}\n","import { QueryError } from \"./errors.js\";\nimport { qualifiedName, quoteIdentifier } from \"./statements.js\";\nimport type { BuiltStatement, SelectSpec, SqlParam } from \"./types.js\";\n\ninterface WhereClause {\n readonly clause: string;\n readonly params: readonly SqlParam[];\n}\n\nfunction buildWhere(where: Readonly<Record<string, SqlParam>> | undefined): WhereClause {\n if (where === undefined) {\n return { clause: \"\", params: [] };\n }\n const entries = Object.entries(where);\n if (entries.length === 0) {\n return { clause: \"\", params: [] };\n }\n const conditions = entries.map(([column]) => `${quoteIdentifier(column)} = ?`);\n return {\n clause: ` WHERE ${conditions.join(\" AND \")}`,\n params: entries.map(([, value]) => value),\n };\n}\n\n/** Build a parameterized `SELECT` statement from a typed spec. */\nexport function buildSelect(spec: SelectSpec): BuiltStatement {\n const columns =\n spec.columns === undefined || spec.columns.length === 0\n ? \"*\"\n : spec.columns.map((column) => quoteIdentifier(column)).join(\", \");\n const where = buildWhere(spec.where);\n const clauses: string[] = [\n `SELECT ${columns} FROM ${qualifiedName(spec.schema, spec.table)}${where.clause}`,\n ];\n\n if (spec.orderBy !== undefined && spec.orderBy.length > 0) {\n clauses.push(`ORDER BY ${spec.orderBy.map((column) => quoteIdentifier(column)).join(\", \")}`);\n }\n if (spec.limit !== undefined) {\n clauses.push(`LIMIT ${String(spec.limit)}`);\n }\n if (spec.offset !== undefined) {\n clauses.push(`OFFSET ${String(spec.offset)}`);\n }\n\n return { sql: clauses.join(\" \"), params: where.params };\n}\n\n/** Build a parameterized `SELECT COUNT(*)` statement. */\nexport function buildCount(\n spec: Pick<SelectSpec, \"schema\" | \"table\" | \"where\">,\n): BuiltStatement {\n const where = buildWhere(spec.where);\n return {\n sql: `SELECT COUNT(*) AS \"COUNT\" FROM ${qualifiedName(spec.schema, spec.table)}${where.clause}`,\n params: where.params,\n };\n}\n\n/** Build a parameterized single-row `INSERT` statement. */\nexport function buildInsert(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const entries = Object.entries(values);\n if (entries.length === 0) {\n throw new QueryError(\"INSERT requires at least one column value\");\n }\n const columns = entries.map(([column]) => quoteIdentifier(column)).join(\", \");\n const placeholders = entries.map(() => \"?\").join(\", \");\n return {\n sql: `INSERT INTO ${qualifiedName(schema, table)} (${columns}) VALUES (${placeholders})`,\n params: entries.map(([, value]) => value),\n };\n}\n\n/** Build a parameterized `UPDATE` statement. A non-empty `where` is required. */\nexport function buildUpdate(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n where: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const valueEntries = Object.entries(values);\n if (valueEntries.length === 0) {\n throw new QueryError(\"UPDATE requires at least one column value\");\n }\n const whereClause = buildWhere(where);\n if (whereClause.clause === \"\") {\n throw new QueryError(\"UPDATE requires a non-empty WHERE filter to avoid a full-table write\");\n }\n const assignments = valueEntries\n .map(([column]) => `${quoteIdentifier(column)} = ?`)\n .join(\", \");\n return {\n sql: `UPDATE ${qualifiedName(schema, table)} SET ${assignments}${whereClause.clause}`,\n params: [...valueEntries.map(([, value]) => value), ...whereClause.params],\n };\n}\n\n/** Build a parameterized `DELETE` statement. A non-empty `where` is required. */\nexport function buildDelete(\n schema: string,\n table: string,\n where: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const whereClause = buildWhere(where);\n if (whereClause.clause === \"\") {\n throw new QueryError(\"DELETE requires a non-empty WHERE filter to avoid a full-table delete\");\n }\n return {\n sql: `DELETE FROM ${qualifiedName(schema, table)}${whereClause.clause}`,\n params: whereClause.params,\n };\n}\n","import type { Connection } from \"./connection.js\";\nimport type { CatalogObjectInfo } from \"./metadata-cache.js\";\nimport type { ColumnInfo, TableInfo } from \"./types.js\";\n\ninterface SchemaRow {\n readonly SCHEMA_NAME: string;\n}\n\ninterface TableRow {\n readonly SCHEMA_NAME: string;\n readonly TABLE_NAME: string;\n readonly TABLE_TYPE: string;\n}\n\ninterface CatalogObjectRow {\n readonly SCHEMA_NAME: string;\n readonly OBJECT_NAME: string;\n readonly OBJECT_TYPE: \"TABLE\" | \"VIEW\";\n}\n\ninterface ColumnRow {\n readonly COLUMN_NAME: string;\n readonly DATA_TYPE_NAME: string;\n readonly LENGTH: number | null;\n readonly SCALE: number | null;\n readonly IS_NULLABLE: string;\n readonly POSITION: number;\n}\n\nexport interface TableDescription {\n readonly table: TableInfo | undefined;\n readonly columns: readonly ColumnInfo[];\n}\n\n/** List every schema visible to the current user. */\nexport async function listSchemas(connection: Connection): Promise<readonly string[]> {\n const result = await connection.query<SchemaRow>(\n \"SELECT SCHEMA_NAME FROM SYS.SCHEMAS ORDER BY SCHEMA_NAME\",\n [],\n { autoLimit: false },\n );\n return result.rows.map((row) => row.SCHEMA_NAME);\n}\n\n/** List the tables in a schema. */\nexport async function listTables(\n connection: Connection,\n schema: string,\n): Promise<readonly TableInfo[]> {\n const result = await connection.query<TableRow>(\n \"SELECT SCHEMA_NAME, TABLE_NAME, TABLE_TYPE FROM SYS.TABLES \" +\n \"WHERE SCHEMA_NAME = ? ORDER BY TABLE_NAME\",\n [schema],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n schema: row.SCHEMA_NAME,\n name: row.TABLE_NAME,\n type: row.TABLE_TYPE,\n rowCount: undefined,\n }));\n}\n\n/** List table and view names in a schema for typo recovery suggestions. */\nexport async function listCatalogObjects(\n connection: Connection,\n schema: string,\n): Promise<readonly CatalogObjectInfo[]> {\n const result = await connection.query<CatalogObjectRow>(\n \"SELECT SCHEMA_NAME, TABLE_NAME AS OBJECT_NAME, 'TABLE' AS OBJECT_TYPE FROM SYS.TABLES \" +\n \"WHERE SCHEMA_NAME = ? UNION ALL \" +\n \"SELECT SCHEMA_NAME, VIEW_NAME AS OBJECT_NAME, 'VIEW' AS OBJECT_TYPE FROM SYS.VIEWS \" +\n \"WHERE SCHEMA_NAME = ? ORDER BY OBJECT_NAME\",\n [schema, schema],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n schema: row.SCHEMA_NAME,\n name: row.OBJECT_NAME,\n type: row.OBJECT_TYPE,\n }));\n}\n\n/** List the columns of a table, ordered by position. */\nexport async function listColumns(\n connection: Connection,\n schema: string,\n table: string,\n): Promise<readonly ColumnInfo[]> {\n const result = await connection.query<ColumnRow>(\n \"SELECT COLUMN_NAME, DATA_TYPE_NAME, LENGTH, SCALE, IS_NULLABLE, POSITION \" +\n \"FROM SYS.TABLE_COLUMNS WHERE SCHEMA_NAME = ? AND TABLE_NAME = ? ORDER BY POSITION\",\n [schema, table],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n name: row.COLUMN_NAME,\n dataType: row.DATA_TYPE_NAME,\n length: row.LENGTH ?? undefined,\n scale: row.SCALE ?? undefined,\n nullable: row.IS_NULLABLE === \"TRUE\",\n position: row.POSITION,\n }));\n}\n\n/** Describe a table: its catalog entry plus its columns. */\nexport async function describeTable(\n connection: Connection,\n schema: string,\n table: string,\n): Promise<TableDescription> {\n const tables = await listTables(connection, schema);\n const columns = await listColumns(connection, schema, table);\n return {\n table: tables.find((info) => info.name === table),\n columns,\n };\n}\n","import { execFile } from \"node:child_process\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nimport type { HanaBinding } from \"./types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nconst MAX_BUFFER = 16 * 1024 * 1024;\nconst DEFAULT_TIMEOUT_MS = 60_000;\nconst CF_RETRY_ATTEMPTS = 3;\nconst CF_RETRY_BASE_DELAY_MS = 500;\n\n/** Minimal context for an isolated CF CLI invocation. */\nexport interface CfExecContext {\n readonly cfHome: string;\n}\n\n/** Data from `cf target`. */\nexport interface CurrentCfTarget {\n readonly apiEndpoint: string;\n readonly orgName: string;\n readonly spaceName: string;\n readonly regionKey?: string;\n}\n\n/** Application identity embedded in the same `cf env` response as service credentials. */\nexport interface CfEnvApplicationIdentity {\n readonly apiEndpoint: string;\n readonly orgName: string;\n readonly spaceName: string;\n readonly appName: string;\n}\n\nconst REGION_API_MAP: Record<string, string> = {\n ae01: \"https://api.cf.ae01.hana.ondemand.com\",\n ap01: \"https://api.cf.ap01.hana.ondemand.com\",\n ap10: \"https://api.cf.ap10.hana.ondemand.com\",\n ap11: \"https://api.cf.ap11.hana.ondemand.com\",\n ap12: \"https://api.cf.ap12.hana.ondemand.com\",\n ap20: \"https://api.cf.ap20.hana.ondemand.com\",\n ap21: \"https://api.cf.ap21.hana.ondemand.com\",\n ap30: \"https://api.cf.ap30.hana.ondemand.com\",\n ap31: \"https://api.cf.ap31.hana.ondemand.com\",\n br10: \"https://api.cf.br10.hana.ondemand.com\",\n br20: \"https://api.cf.br20.hana.ondemand.com\",\n br30: \"https://api.cf.br30.hana.ondemand.com\",\n ca10: \"https://api.cf.ca10.hana.ondemand.com\",\n ca20: \"https://api.cf.ca20.hana.ondemand.com\",\n ch20: \"https://api.cf.ch20.hana.ondemand.com\",\n cn20: \"https://api.cf.cn20.platform.sapcloud.cn\",\n cn40: \"https://api.cf.cn40.platform.sapcloud.cn\",\n eu01: \"https://api.cf.eu01.hana.ondemand.com\",\n eu02: \"https://api.cf.eu02.hana.ondemand.com\",\n eu10: \"https://api.cf.eu10.hana.ondemand.com\",\n \"eu10-002\": \"https://api.cf.eu10-002.hana.ondemand.com\",\n \"eu10-003\": \"https://api.cf.eu10-003.hana.ondemand.com\",\n \"eu10-004\": \"https://api.cf.eu10-004.hana.ondemand.com\",\n \"eu10-005\": \"https://api.cf.eu10-005.hana.ondemand.com\",\n \"eu10-006\": \"https://api.cf.eu10-006.hana.ondemand.com\",\n eu11: \"https://api.cf.eu11.hana.ondemand.com\",\n eu12: \"https://api.cf.eu12.hana.ondemand.com\",\n eu13: \"https://api.cf.eu13.hana.ondemand.com\",\n eu20: \"https://api.cf.eu20.hana.ondemand.com\",\n \"eu20-001\": \"https://api.cf.eu20-001.hana.ondemand.com\",\n \"eu20-002\": \"https://api.cf.eu20-002.hana.ondemand.com\",\n eu21: \"https://api.cf.eu21.hana.ondemand.com\",\n eu22: \"https://api.cf.eu22.hana.ondemand.com\",\n eu30: \"https://api.cf.eu30.hana.ondemand.com\",\n eu31: \"https://api.cf.eu31.hana.ondemand.com\",\n il30: \"https://api.cf.il30.hana.ondemand.com\",\n in30: \"https://api.cf.in30.hana.ondemand.com\",\n jp01: \"https://api.cf.jp01.hana.ondemand.com\",\n jp10: \"https://api.cf.jp10.hana.ondemand.com\",\n jp20: \"https://api.cf.jp20.hana.ondemand.com\",\n jp30: \"https://api.cf.jp30.hana.ondemand.com\",\n jp31: \"https://api.cf.jp31.hana.ondemand.com\",\n sa30: \"https://api.cf.sa30.hana.ondemand.com\",\n sa31: \"https://api.cf.sa31.hana.ondemand.com\",\n uk20: \"https://api.cf.uk20.hana.ondemand.com\",\n us01: \"https://api.cf.us01.hana.ondemand.com\",\n us02: \"https://api.cf.us02.hana.ondemand.com\",\n us10: \"https://api.cf.us10.hana.ondemand.com\",\n \"us10-001\": \"https://api.cf.us10-001.hana.ondemand.com\",\n \"us10-002\": \"https://api.cf.us10-002.hana.ondemand.com\",\n \"us10-003\": \"https://api.cf.us10-003.hana.ondemand.com\",\n us11: \"https://api.cf.us11.hana.ondemand.com\",\n us20: \"https://api.cf.us20.hana.ondemand.com\",\n us21: \"https://api.cf.us21.hana.ondemand.com\",\n \"us21-001\": \"https://api.cf.us21-001.hana.ondemand.com\",\n us22: \"https://api.cf.us22.hana.ondemand.com\",\n us30: \"https://api.cf.us30.hana.ondemand.com\",\n us32: \"https://api.cf.us32.hana.ondemand.com\",\n};\n\nexport function normalizeSapCfApiEndpoint(apiEndpoint: string): string {\n const trimmed = apiEndpoint.trim();\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n if (/^https:\\/\\/[^/]*:\\d+(?:[/?#]|$)/i.test(trimmed)) {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n if (\n parsed.protocol !== \"https:\" ||\n parsed.username !== \"\" ||\n parsed.password !== \"\" ||\n parsed.port !== \"\" ||\n parsed.pathname.replace(/(?<!\\/)\\/+$/, \"\") !== \"\" ||\n parsed.search !== \"\" ||\n parsed.hash !== \"\"\n ) {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n const hostname = parsed.hostname.toLowerCase();\n const match = /^api\\.cf\\.([a-z]{2}\\d{2}(?:-\\d{3})?)\\.(hana\\.ondemand\\.com|platform\\.sapcloud\\.cn)$/.exec(hostname);\n if (!match) {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n return `https://${hostname}`;\n}\n\nexport function getApiEndpointForRegion(regionKey: string): string | undefined {\n return REGION_API_MAP[regionKey.trim().toLowerCase()];\n}\n\nexport function getRegionKeyForApi(apiEndpoint: string): string | undefined {\n let normalized: string;\n try {\n normalized = normalizeSapCfApiEndpoint(apiEndpoint);\n } catch {\n return undefined;\n }\n for (const [key, endpoint] of Object.entries(REGION_API_MAP)) {\n if (endpoint.toLowerCase() === normalized) {\n return key;\n }\n }\n return /^https:\\/\\/api\\.cf\\.([a-z]{2}\\d{2}(?:-\\d{3})?)\\.hana\\.ondemand\\.com$/.exec(normalized)?.[1];\n}\n\n/** Run work inside a fresh temporary CF_HOME. Directory is always cleaned. */\nexport async function withCfSession<T>(work: (ctx: CfExecContext) => Promise<T>): Promise<T> {\n const cfHome = await mkdtemp(join(tmpdir(), \"saptools-cf-hana-\"));\n const ctx: CfExecContext = { cfHome };\n try {\n return await work(ctx);\n } finally {\n await rm(cfHome, { recursive: true, force: true });\n }\n}\n\nexport function resolveCfBin(): { bin: string; argsPrefix: readonly string[] } {\n const raw = process.env[\"CF_HANA_CF_BIN\"] ?? \"cf\";\n if (/\\.(?:c|m)?js$/i.test(raw)) {\n return { bin: process.execPath, argsPrefix: [raw] };\n }\n return { bin: raw, argsPrefix: [] };\n}\n\nfunction buildEnv(ctx: CfExecContext, overrides: Record<string, string> = {}): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...process.env, ...overrides };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n env[\"CF_HOME\"] = ctx.cfHome;\n return env;\n}\n\nasync function execWithRetries(\n bin: string,\n args: readonly string[],\n env: NodeJS.ProcessEnv,\n timeoutMs: number = DEFAULT_TIMEOUT_MS\n): Promise<string> {\n let lastErr: unknown;\n for (let attempt = 0; attempt < CF_RETRY_ATTEMPTS; attempt++) {\n try {\n const { stdout } = await execFileAsync(bin, args, {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: timeoutMs,\n killSignal: \"SIGKILL\",\n });\n return stdout;\n } catch (err) {\n lastErr = err;\n \n const e = err as { killed?: boolean; code?: number | string; stderr?: string | Buffer; message?: string };\n const output = `${e.message ?? \"\"} ${e.stderr ? String(e.stderr) : \"\"}`.toLowerCase();\n \n const isTimeout = e.killed === true; \n const isNetworkFlake = \n output.includes(\"error performing request\") ||\n output.includes(\"timeout\") ||\n output.includes(\"connection reset\") ||\n output.includes(\"connection refused\") ||\n output.includes(\"eof\") ||\n output.includes(\"502 bad gateway\") ||\n output.includes(\"503 service unavailable\") ||\n output.includes(\"504 gateway timeout\") ||\n output.includes(\"dial tcp\") ||\n output.includes(\"no such host\");\n \n const isEnoent = e.code === \"ENOENT\";\n if (isEnoent || (!isTimeout && !isNetworkFlake)) {\n throw err; // Fail fast for user errors or missing binary\n }\n\n if (attempt < CF_RETRY_ATTEMPTS - 1) {\n await new Promise((r) => setTimeout(r, CF_RETRY_BASE_DELAY_MS * (attempt + 1)));\n }\n }\n }\n throw lastErr;\n}\n\nasync function runCf(\n args: readonly string[],\n ctx: CfExecContext,\n overrides: Record<string, string> = {},\n): Promise<string> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = buildEnv(ctx, overrides);\n\n try {\n return await execWithRetries(bin, [...argsPrefix, ...args], env);\n } catch (lastErr) {\n const e = lastErr as { stderr?: string | Buffer; message?: string } | undefined;\n const detail = e?.stderr ? String(e.stderr) : (e?.message ?? \"\");\n const cmd = args[0] === \"auth\" ? \"cf auth\" : `cf ${args.join(\" \")}`;\n throw new Error(`${cmd} failed: ${detail}`.trim(), { cause: lastErr });\n }\n}\n\nexport async function cfApi(apiEndpoint: string, ctx: CfExecContext): Promise<void> {\n await runCf([\"api\", apiEndpoint], ctx);\n}\n\n/** Auth using env vars (professional, matches cf-events pattern). */\nexport async function cfAuth(email: string, password: string, ctx: CfExecContext): Promise<void> {\n await runCf([\"auth\"], ctx, {\n CF_USERNAME: email,\n CF_PASSWORD: password,\n });\n}\n\nexport async function cfTargetSpace(\n orgName: string,\n spaceName: string,\n ctx: CfExecContext,\n): Promise<void> {\n await runCf([\"target\", \"-o\", orgName, \"-s\", spaceName], ctx);\n}\n\nexport async function cfEnv(appName: string, ctx: CfExecContext): Promise<string> {\n return await runCf([\"env\", appName], ctx);\n}\n\n/**\n * Direct current user CF context for bare app names.\n * No isolated CF_HOME or forced re-authentication: the current target supplies the app scope.\n */\nexport async function cfEnvDirect(appName: string): Promise<string> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = { ...process.env };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n return await execWithRetries(bin, [...argsPrefix, \"env\", appName], env);\n}\n\n/** List apps in the target org/space, isolated context (tunnel jump-host discovery). */\nexport async function cfApps(ctx: CfExecContext): Promise<string> {\n return await runCf([\"apps\"], ctx);\n}\n\n/** List apps in the current ambient target, no CF_HOME override (mirrors {@link cfEnvDirect}). */\nexport async function cfAppsDirect(): Promise<string> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = { ...process.env };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n return await execWithRetries(bin, [...argsPrefix, \"apps\"], env);\n}\n\nexport async function readCurrentCfTarget(): Promise<CurrentCfTarget | undefined> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = { ...process.env };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n\n try {\n const stdout = await execWithRetries(bin, [...argsPrefix, \"target\"], env);\n return parseCfTargetOutput(stdout);\n } catch {\n return undefined;\n }\n}\n\nexport function parseCfTargetOutput(stdout: string): CurrentCfTarget | undefined {\n const fields = parseTargetFields(stdout);\n const api = fields.get(\"api endpoint\");\n const org = fields.get(\"org\");\n const space = fields.get(\"space\");\n if (!api || !org || !space) {\n return undefined;\n }\n let normalizedApi: string;\n try {\n normalizedApi = normalizeSapCfApiEndpoint(api);\n } catch {\n return undefined;\n }\n const regionKey = getRegionKeyForApi(normalizedApi);\n return {\n apiEndpoint: normalizedApi,\n orgName: org,\n spaceName: space,\n ...(regionKey ? { regionKey } : {}),\n };\n}\n\nfunction parseTargetFields(stdout: string): Map<string, string> {\n const map = new Map<string, string>();\n for (const line of stdout.split(/\\r?\\n/)) {\n const idx = line.indexOf(\":\");\n if (idx < 0) {continue;}\n const key = line.slice(0, idx).trim().toLowerCase();\n const val = line.slice(idx + 1).trim();\n if (key && val) {map.set(key, val);}\n }\n return map;\n}\n\nexport interface CfAppRow {\n readonly name: string;\n readonly state: string;\n}\n\n/**\n * Parses `cf apps` table output. This is a display table, not a stable\n * machine format, so parsing stays deliberately tolerant: it looks for a\n * header row starting with \"name\" and reads the first two whitespace-\n * delimited columns (name, requested state) from every non-blank row after\n * it, ignoring anything it doesn't recognize rather than throwing.\n */\nexport function parseCfAppsOutput(stdout: string): readonly CfAppRow[] {\n const lines = stdout.split(/\\r?\\n/);\n const headerIndex = lines.findIndex((line) => /^\\s*name\\s+\\S/i.test(line));\n if (headerIndex === -1) {\n return [];\n }\n const rows: CfAppRow[] = [];\n for (const line of lines.slice(headerIndex + 1)) {\n const trimmed = line.trim();\n if (trimmed.length === 0) {\n continue;\n }\n const [name, state] = trimmed.split(/\\s+/);\n if (name === undefined || state === undefined) {\n continue;\n }\n rows.push({ name, state });\n }\n return rows;\n}\n\nexport function formatCurrentCfAppSelector(target: CurrentCfTarget, appName: string): string {\n const name = appName.trim();\n if (!name) {throw new Error(\"App name is required.\");}\n const region = target.regionKey ?? \"current\";\n return `${region}/${target.orgName}/${target.spaceName}/${name}`;\n}\n\n/* VCAP parser */\n\nfunction findJsonObjectEnd(source: string, startIndex: number): number {\n let depth = 0;\n let inString = false;\n let escaped = false;\n for (let index = startIndex; index < source.length; index++) {\n const character = source[index];\n if (escaped) {\n escaped = false;\n continue;\n }\n if (inString && character === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (character === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) {continue;}\n if (character === \"{\") {\n depth++;\n continue;\n }\n if (character === \"}\" && --depth === 0) {return index;}\n }\n return -1;\n}\n\nfunction extractVcapApplicationJson(stdout: string): string {\n const marker = \"VCAP_APPLICATION:\";\n const markerIndex = stdout.indexOf(marker);\n if (markerIndex === -1) {\n throw new Error(\"VCAP_APPLICATION section not found in cf env output\");\n }\n const afterMarker = stdout.slice(markerIndex + marker.length);\n const openIndex = afterMarker.indexOf(\"{\");\n if (openIndex === -1) {\n throw new Error(\"VCAP_APPLICATION JSON payload not found in cf env output\");\n }\n const closeIndex = findJsonObjectEnd(afterMarker, openIndex);\n if (closeIndex === -1) {\n throw new Error(\"Malformed VCAP_APPLICATION JSON in cf env output\");\n }\n return afterMarker.slice(openIndex, closeIndex + 1);\n}\n\nfunction requireApplicationField(\n application: Record<string, unknown>,\n field: string,\n): string {\n const value = application[field];\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new Error(`VCAP_APPLICATION.${field} must be a non-empty string`);\n }\n return value.trim();\n}\n\nexport function extractCfEnvApplicationIdentity(stdout: string): CfEnvApplicationIdentity {\n let application: unknown;\n try {\n application = JSON.parse(extractVcapApplicationJson(stdout));\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(\"VCAP_APPLICATION is not valid JSON\", { cause: error });\n }\n throw error;\n }\n if (!isRecord(application)) {throw new Error(\"VCAP_APPLICATION must be an object\");}\n return {\n appName: requireApplicationField(application, \"application_name\"),\n apiEndpoint: normalizeSapCfApiEndpoint(requireApplicationField(application, \"cf_api\")),\n orgName: requireApplicationField(application, \"organization_name\"),\n spaceName: requireApplicationField(application, \"space_name\"),\n };\n}\n\nfunction extractVcapSection(stdout: string): string {\n const start = stdout.indexOf(\"VCAP_SERVICES:\");\n if (start === -1) {throw new Error(\"VCAP_SERVICES section not found in cf env output\");}\n const after = stdout.slice(start + \"VCAP_SERVICES:\".length);\n const end = after.indexOf(\"VCAP_APPLICATION:\");\n const block = end === -1 ? after : after.slice(0, end);\n return block.trim();\n}\n\ninterface RawHanaCreds {\n host: string;\n port: string;\n user: string;\n password: string;\n schema: string;\n hdi_user: string;\n hdi_password: string;\n url: string;\n database_id: string;\n certificate: string;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction assertCreds(raw: unknown): RawHanaCreds {\n if (!isRecord(raw)) {throw new Error(\"HANA credentials must be an object\");}\n const req = [\"host\", \"port\", \"user\", \"password\", \"schema\", \"hdi_user\", \"hdi_password\", \"url\", \"database_id\", \"certificate\"];\n for (const k of req) {\n if (typeof raw[k] !== \"string\") {throw new Error(`Missing/invalid HANA credential field: \"${k}\"`);}\n }\n return raw as unknown as RawHanaCreds;\n}\n\nfunction mapCreds(raw: RawHanaCreds): HanaBinding[\"credentials\"] {\n return {\n host: raw.host,\n port: raw.port,\n user: raw.user,\n password: raw.password,\n schema: raw.schema,\n hdiUser: raw.hdi_user,\n hdiPassword: raw.hdi_password,\n ...(raw.url ? { url: raw.url } : {}),\n databaseId: raw.database_id,\n certificate: raw.certificate,\n };\n}\n\nexport function extractHanaBindingsFromCfEnv(stdout: string): readonly HanaBinding[] {\n const jsonText = extractVcapSection(stdout);\n let vcap: unknown;\n try {\n vcap = JSON.parse(jsonText);\n } catch {\n throw new Error(\"VCAP_SERVICES is not valid JSON\");\n }\n if (!isRecord(vcap)) {throw new Error(\"VCAP_SERVICES must be an object\");}\n\n const hana = vcap[\"hana\"];\n if (hana === undefined) {return [];}\n if (!Array.isArray(hana)) {throw new Error(\"VCAP_SERVICES.hana must be an array when present\");}\n\n return hana.map((b: unknown) => {\n if (!isRecord(b)) {throw new Error(\"HANA binding must be an object\");}\n const credsRaw = assertCreds(b[\"credentials\"]);\n const name = typeof b[\"name\"] === \"string\" ? b[\"name\"] : undefined;\n return {\n ...(name ? { name } : {}),\n credentials: mapCreds(credsRaw),\n } as HanaBinding;\n });\n}\n\n/**\n * Professional classification: only re-auth for real session/unauth problems.\n */\nexport function classifyCfError(stderr: string | undefined = \"\", stdout: string | undefined = \"\"): {\n readonly isAuthError: boolean;\n readonly reason: string;\n} {\n const text = `${stderr} ${stdout}`.toLowerCase();\n if (\n text.includes(\"not logged in\") ||\n text.includes(\"unauthorized\") ||\n text.includes(\"forbidden\") ||\n text.includes(\"credentials were rejected\") ||\n text.includes(\"authentication failed\") ||\n text.includes(\"cf auth\") ||\n text.includes(\"token\") ||\n text.includes(\"expired\") ||\n text.includes(\"session\")\n ) {\n return { isAuthError: true, reason: \"auth/session issue\" };\n }\n return { isAuthError: false, reason: \"\" };\n}\n","import {\n cfApi,\n cfAuth,\n cfEnv,\n cfEnvDirect,\n cfTargetSpace,\n classifyCfError,\n extractCfEnvApplicationIdentity,\n extractHanaBindingsFromCfEnv,\n formatCurrentCfAppSelector,\n getApiEndpointForRegion,\n normalizeSapCfApiEndpoint,\n readCurrentCfTarget,\n withCfSession,\n} from \"./cf.js\";\nimport type { CfEnvApplicationIdentity } from \"./cf.js\";\nimport { readSapCredentials } from \"./config.js\";\nimport type { SapCredentials } from \"./config.js\";\nimport { CfHanaError, CredentialsNotFoundError } from \"./errors.js\";\nimport type { CredentialSource, DbUserRole, HanaBinding, SelectorSource } from \"./types.js\";\n\nexport interface ResolveBindingsOptions {\n /** Deprecated compatibility flag. Binding discovery is always live. */\n readonly refresh?: boolean;\n readonly email?: string;\n readonly password?: string;\n}\n\nfunction errorMessageFromUnknown(error: unknown): string {\n return error instanceof Error ? error.message : \"Invalid or untrusted CF API endpoint.\";\n}\n\nexport interface ResolvedBindings {\n readonly selector: string;\n readonly appName: string;\n readonly bindings: readonly HanaBinding[];\n readonly source: CredentialSource;\n readonly selectorSource: SelectorSource;\n readonly regionConfirmed: boolean;\n readonly selectorCanBePinned: boolean;\n readonly apiEndpoint: string;\n readonly orgName: string;\n readonly spaceName: string;\n}\n\ninterface ResolvedAppTarget {\n readonly selector: string;\n readonly apiEndpoint: string;\n readonly orgName: string;\n readonly spaceName: string;\n readonly appName: string;\n readonly selectorSource: SelectorSource;\n readonly regionConfirmed: boolean;\n readonly selectorCanBePinned: boolean;\n}\n\nexport interface BindingSelector {\n readonly bindingName?: string;\n readonly bindingIndex?: number;\n}\n\nexport interface SelectedConnectionTarget {\n readonly host: string;\n readonly port: number;\n readonly user: string;\n readonly password: string;\n readonly schema: string;\n readonly certificate: string;\n readonly databaseId: string;\n}\n\nfunction parseExplicitTarget(selector: string): ResolvedAppTarget {\n const [regionKey, orgName, spaceName, appName, extra] = selector\n .split(\"/\")\n .map((part) => part.trim());\n if (extra !== undefined || !regionKey || !orgName || !spaceName || !appName) {\n throw new CfHanaError(\n \"CONFIG\",\n `Invalid selector \"${selector}\". Use region/org/space/app or a bare app name.`,\n );\n }\n const apiEndpoint = getApiEndpointForRegion(regionKey);\n if (apiEndpoint === undefined) {\n throw new CfHanaError(\n \"CONFIG\",\n `Unknown SAP CF region \"${regionKey}\". Verify the current SAP region list or use the current CF target.`,\n );\n }\n try {\n return {\n selector,\n apiEndpoint: normalizeSapCfApiEndpoint(apiEndpoint),\n orgName,\n spaceName,\n appName,\n selectorSource: \"explicit\",\n regionConfirmed: true,\n selectorCanBePinned: true,\n };\n } catch (error) {\n throw new CfHanaError(\"CONFIG\", errorMessageFromUnknown(error), { cause: error });\n }\n}\n\nasync function resolveTarget(selector: string): Promise<ResolvedAppTarget> {\n if (selector.includes(\"/\")) {\n return parseExplicitTarget(selector);\n }\n const current = await readCurrentCfTarget();\n if (current === undefined) {\n throw new CfHanaError(\n \"CONFIG\",\n \"No current CF target found. Run `cf target -o <org> -s <space>` or pass a full region/org/space/app selector.\",\n );\n }\n return {\n selector: formatCurrentCfAppSelector(current, selector),\n apiEndpoint: current.apiEndpoint,\n orgName: current.orgName,\n spaceName: current.spaceName,\n appName: selector,\n selectorSource: \"ambient\",\n regionConfirmed: current.regionKey !== undefined,\n selectorCanBePinned:\n current.regionKey !== undefined && getApiEndpointForRegion(current.regionKey) !== undefined,\n };\n}\n\nfunction commandErrorText(error: unknown): string {\n if (typeof error !== \"object\" || error === null) {\n return \"\";\n }\n if (\"stderr\" in error && typeof error.stderr === \"string\" && error.stderr.length > 0) {\n return error.stderr;\n }\n return \"message\" in error && typeof error.message === \"string\" ? error.message : \"\";\n}\n\nfunction isSameTarget(\n target: ResolvedAppTarget,\n current: Awaited<ReturnType<typeof readCurrentCfTarget>>,\n): boolean {\n return (\n current?.apiEndpoint === target.apiEndpoint &&\n current.orgName === target.orgName &&\n current.spaceName === target.spaceName\n );\n}\n\nasync function assertAmbientTargetUnchanged(target: ResolvedAppTarget): Promise<void> {\n const current = await readCurrentCfTarget();\n if (!isSameTarget(target, current)) {\n throw new CfHanaError(\n \"CONFIG\",\n \"CF target changed during binding discovery; no database connection was opened. Retry or use an explicit region/org/space/app selector.\",\n );\n }\n}\n\nfunction readCfEnvApplicationIdentity(stdout: string): CfEnvApplicationIdentity {\n try {\n return extractCfEnvApplicationIdentity(stdout);\n } catch (error) {\n throw new CfHanaError(\n \"CONFIG\",\n \"Could not verify cf env application identity for the ambient target; no database connection was opened. \" +\n \"Retry or use an explicit region/org/space/app selector.\",\n { cause: error },\n );\n }\n}\n\nfunction assertCfEnvApplicationMatchesTarget(\n target: ResolvedAppTarget,\n application: CfEnvApplicationIdentity,\n): void {\n const matches =\n application.apiEndpoint === target.apiEndpoint &&\n application.orgName === target.orgName &&\n application.spaceName === target.spaceName &&\n application.appName === target.appName;\n if (matches) {return;}\n throw new CfHanaError(\n \"CONFIG\",\n \"CF env application identity did not match the resolved ambient target; no database connection was opened. \" +\n \"Retry or use an explicit region/org/space/app selector.\",\n );\n}\n\nasync function readIsolatedBindings(\n target: ResolvedAppTarget,\n sap: SapCredentials,\n): Promise<readonly HanaBinding[]> {\n return await withCfSession(async (ctx) => {\n await cfApi(target.apiEndpoint, ctx);\n await cfAuth(sap.email, sap.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n return extractHanaBindingsFromCfEnv(await cfEnv(target.appName, ctx));\n });\n}\n\nasync function readBareBindings(\n target: ResolvedAppTarget,\n options: ResolveBindingsOptions,\n): Promise<readonly HanaBinding[]> {\n let stdout: string;\n try {\n stdout = await cfEnvDirect(target.appName);\n } catch (directError) {\n const classified = classifyCfError(commandErrorText(directError));\n if (!classified.isAuthError) {\n throw new CfHanaError(\n \"CONFIG\",\n `Failed to get HANA bindings for bare app \"${target.appName}\" using current target (org=${target.orgName}, space=${target.spaceName}). ` +\n `Verify with \"cf target\" and \"cf env ${target.appName}\".`,\n { cause: directError },\n );\n }\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (sap === undefined) {\n throw new CredentialsNotFoundError(\n `Current CF session problem for bare app \"${target.appName}\" (${classified.reason}).\\n` +\n `Run \"cf login\" + \"cf target\", or provide SAP_EMAIL + SAP_PASSWORD.`,\n { cause: directError },\n );\n }\n return await readIsolatedBindings(target, sap);\n }\n const application = readCfEnvApplicationIdentity(stdout);\n await assertAmbientTargetUnchanged(target);\n assertCfEnvApplicationMatchesTarget(target, application);\n return extractHanaBindingsFromCfEnv(stdout);\n}\n\n/** Resolve every HANA binding for a pinned selector or the current CF target. */\nexport async function resolveAppBindings(\n rawSelector: string,\n options: ResolveBindingsOptions,\n): Promise<ResolvedBindings> {\n const selector = rawSelector.trim();\n if (selector.length === 0) {\n throw new CfHanaError(\"CONFIG\", \"App selector is required\");\n }\n const target = await resolveTarget(selector);\n const bindings =\n target.selectorSource === \"ambient\"\n ? await readBareBindings(target, options)\n : await readExplicitBindings(target, options);\n if (bindings.length === 0) {\n throw new CredentialsNotFoundError(`App \"${target.selector}\" has no HANA service binding.`);\n }\n return {\n selector: target.selector,\n appName: target.appName,\n bindings,\n source: \"live\",\n selectorSource: target.selectorSource,\n regionConfirmed: target.regionConfirmed,\n selectorCanBePinned: target.selectorCanBePinned,\n apiEndpoint: target.apiEndpoint,\n orgName: target.orgName,\n spaceName: target.spaceName,\n };\n}\n\nasync function readExplicitBindings(\n target: ResolvedAppTarget,\n options: ResolveBindingsOptions,\n): Promise<readonly HanaBinding[]> {\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (sap === undefined) {\n throw new CredentialsNotFoundError(\n `SAP_EMAIL and SAP_PASSWORD are required to fetch HANA bindings for explicit selector \"${target.selector}\".`,\n );\n }\n return await readIsolatedBindings(target, sap);\n}\n\n/** Pick a single HANA binding from an app's bindings. */\nexport function selectBinding(\n bindings: readonly HanaBinding[],\n selector: BindingSelector,\n): HanaBinding {\n if (selector.bindingName !== undefined) {\n const match = bindings.find((binding) => binding.name === selector.bindingName);\n if (match === undefined) {\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `No HANA binding named \"${selector.bindingName}\"`,\n );\n }\n return match;\n }\n\n if (selector.bindingIndex !== undefined) {\n const match = bindings[selector.bindingIndex];\n if (match === undefined) {\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `No HANA binding at index ${String(selector.bindingIndex)}`,\n );\n }\n return match;\n }\n\n const first = bindings[0];\n if (first === undefined) {\n throw new CredentialsNotFoundError(\"No HANA bindings are available for this app\");\n }\n if (bindings.length > 1) {\n const labels = bindings\n .map((binding, index) => binding.name ?? `#${String(index)}`)\n .join(\", \");\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `App has multiple HANA bindings (${labels}); ` +\n `choose one with bindingName or bindingIndex`,\n );\n }\n return first;\n}\n\n/** Map a HANA binding to concrete connection parameters for the chosen role. */\nexport function toConnectionTarget(\n binding: HanaBinding,\n role: DbUserRole,\n): SelectedConnectionTarget {\n const credentials = binding.credentials;\n const port = Number.parseInt(credentials.port, 10);\n if (!Number.isInteger(port) || port <= 0) {\n throw new CfHanaError(\"CONFIG\", `Invalid HANA port in binding: \"${credentials.port}\"`);\n }\n return {\n host: credentials.host,\n port,\n user: role === \"hdi\" ? credentials.hdiUser : credentials.user,\n password: role === \"hdi\" ? credentials.hdiPassword : credentials.password,\n schema: credentials.schema,\n certificate: credentials.certificate,\n databaseId: credentials.databaseId ?? \"\",\n };\n}\n","import { appendFile } from \"node:fs/promises\";\n\nimport { envName, readEnv } from \"../config.js\";\nimport { CfHanaError, QueryError } from \"../errors.js\";\nimport { classifyStatement } from \"../statements.js\";\nimport type { SqlParam, StatementKind } from \"../types.js\";\n\nimport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\nlet catalogFailureInjected = false;\nlet connectFailureInjectedOnce = false;\n\n/**\n * Deterministic in-memory driver used by hermetic end-to-end tests and offline\n * smoke checks. Selected via `CF_HANA_DRIVER=fake`. It never opens a socket.\n */\ninterface FakeCatalogObjectRow extends Record<string, SqlParam> {\n readonly SCHEMA_NAME: string;\n readonly OBJECT_NAME: string;\n readonly OBJECT_TYPE: \"TABLE\" | \"VIEW\";\n}\n\nfunction catalogObjects(): readonly FakeCatalogObjectRow[] {\n return [\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"EXISTING_TABLE\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"MISSING_TABLE_FIXED\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"MISSING_TABLE_VIEW\", OBJECT_TYPE: \"VIEW\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"STATUS_ITEMS\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"CORE_AUTH_SCOPE\", OBJECT_TYPE: \"TABLE\" },\n ];\n}\n\nfunction tableColumns(): readonly Record<string, SqlParam>[] {\n return [\n { COLUMN_NAME: \"ID\", DATA_TYPE_NAME: \"INTEGER\", LENGTH: null, SCALE: null, IS_NULLABLE: \"FALSE\", POSITION: 1 },\n { COLUMN_NAME: \"IS_ACTIVE\", DATA_TYPE_NAME: \"BOOLEAN\", LENGTH: null, SCALE: null, IS_NULLABLE: \"TRUE\", POSITION: 2 },\n { COLUMN_NAME: \"SCOPE_NAME\", DATA_TYPE_NAME: \"NVARCHAR\", LENGTH: 255, SCALE: null, IS_NULLABLE: \"TRUE\", POSITION: 3 },\n ];\n}\n\nfunction throwForcedFailure(kind: StatementKind): void {\n const forcedFailure = readEnv(envName(\"FAKE_FAIL_STATEMENT\"))?.toLowerCase();\n if (forcedFailure === kind) {\n throw new Error(`fake driver forced ${kind.toUpperCase()} failure`);\n }\n}\n\nfunction throwEarlyFixtureError(upperSql: string): void {\n if (upperSql.includes(\"PRIVILEGE_ERROR_CODE\")) {\n throw new QueryError(\"insufficient privilege: not authorized\", { databaseCode: 258 });\n }\n if (upperSql.includes(\"PRIVILEGE_ERROR_MESSAGE\")) {\n throw new QueryError(\"insufficient privilege: grant is missing\");\n }\n if (upperSql.includes(\"NON_PRIVILEGE_ERROR\")) {\n throw new QueryError(\"fake unrelated query failure\", { databaseCode: 999 });\n }\n if (\n readEnv(envName(\"FAKE_PRIVILEGE_CATALOG\")) === \"1\" &&\n (upperSql.includes(\"SYS.TABLES\") || upperSql.includes(\"SYS.TABLE_COLUMNS\"))\n ) {\n throw new QueryError(\"insufficient privilege: catalog access denied\", { databaseCode: 258 });\n }\n}\n\nfunction catalogObjectsResult(): DriverExecResult {\n return {\n rows: catalogObjects(),\n columns: [\n { name: \"SCHEMA_NAME\", typeName: \"NVARCHAR\" },\n { name: \"OBJECT_NAME\", typeName: \"NVARCHAR\" },\n { name: \"OBJECT_TYPE\", typeName: \"NVARCHAR\" },\n ],\n affectedRows: 0,\n };\n}\n\nfunction tablesResult(): DriverExecResult {\n return {\n rows: [\n { SCHEMA_NAME: \"APP_SCHEMA\", TABLE_NAME: \"EXISTING_TABLE\", TABLE_TYPE: \"COLUMN TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", TABLE_NAME: \"STATUS_ITEMS\", TABLE_TYPE: \"ROW TABLE\" },\n ],\n columns: [\n { name: \"SCHEMA_NAME\", typeName: \"NVARCHAR\" },\n { name: \"TABLE_NAME\", typeName: \"NVARCHAR\" },\n { name: \"TABLE_TYPE\", typeName: \"NVARCHAR\" },\n ],\n affectedRows: 0,\n };\n}\n\nfunction tableColumnsResult(): DriverExecResult {\n return {\n rows: tableColumns(),\n columns: [\n { name: \"COLUMN_NAME\", typeName: \"NVARCHAR\" },\n { name: \"DATA_TYPE_NAME\", typeName: \"NVARCHAR\" },\n { name: \"LENGTH\", typeName: \"INTEGER\" },\n { name: \"SCALE\", typeName: \"INTEGER\" },\n { name: \"IS_NULLABLE\", typeName: \"NVARCHAR\" },\n { name: \"POSITION\", typeName: \"INTEGER\" },\n ],\n affectedRows: 0,\n };\n}\n\nfunction matchCatalogFixture(upperSql: string): DriverExecResult | undefined {\n if (upperSql.includes(\"SYS.TABLES\") && upperSql.includes(\"SYS.VIEWS\")) {\n if (readEnv(envName(\"FAKE_FAIL_CATALOG_ONCE\")) === \"1\" && !catalogFailureInjected) {\n catalogFailureInjected = true;\n throw new QueryError(\"fake transient catalog metadata failure\");\n }\n return catalogObjectsResult();\n }\n if (upperSql.includes(\"SYS.TABLES\")) {\n return tablesResult();\n }\n if (upperSql.includes(\"SYS.TABLE_COLUMNS\")) {\n return tableColumnsResult();\n }\n return void 0;\n}\n\nfunction throwLateFixtureError(upperSql: string): void {\n if (upperSql.includes(\"MISSING_TABLE\") || upperSql.includes(\"MISSING_TABLES\")) {\n throw new QueryError(\"invalid table name: MISSING_TABLE\", { sqlState: \"42S02\" });\n }\n if (upperSql.includes(\"ISACTIVE\")) {\n throw new QueryError(\"invalid column name: ISACTIVE: line 1 col 8 (at pos 7)\", { databaseCode: 260 });\n }\n if (upperSql.includes(\"LOB_ORDER_ERROR\")) {\n throw new QueryError(\"inconsistent datatype: LOB type is not allowed in ORDER BY clause\", { databaseCode: 266 });\n }\n if (upperSql.includes(\"LOB_GROUP_ERROR\")) {\n throw new QueryError(\"inconsistent datatype: LOB type is not allowed in GROUP BY clause\", { databaseCode: 274 });\n }\n}\n\nfunction lobFixtureResult(): DriverExecResult {\n return {\n rows: [\n {\n LOG_CONTENT: Buffer.from(\"Example log entry\", \"utf8\"),\n CLOB_CONTENT: Buffer.from(\"Clob log entry\", \"utf8\"),\n PAYLOAD: Buffer.from([0, 1, 2, 255]),\n },\n ],\n columns: [\n { name: \"LOG_CONTENT\", typeName: \"NCLOB\" },\n { name: \"CLOB_CONTENT\", typeName: \"CLOB\" },\n { name: \"PAYLOAD\", typeName: \"BLOB\" },\n ],\n affectedRows: 0,\n };\n}\n\nfunction matchDataFixture(upperSql: string): DriverExecResult | undefined {\n if (upperSql.includes(\"LOB_FIXTURE\")) {\n return lobFixtureResult();\n }\n if (upperSql.includes(\"SINGLE_COLUMN_FIXTURE\")) {\n return {\n rows: [{ VALUE: \"alpha\" }, { VALUE: \"beta\" }],\n columns: [{ name: \"VALUE\", typeName: \"NVARCHAR\" }],\n affectedRows: 0,\n };\n }\n if (upperSql.includes(\"DUMMY\")) {\n return {\n rows: [{ \"1\": 1 }],\n columns: [{ name: \"1\", typeName: \"INTEGER\" }],\n affectedRows: 0,\n };\n }\n return void 0;\n}\n\nfunction defaultResult(kind: StatementKind): DriverExecResult {\n if (kind === \"select\") {\n return {\n rows: [\n { ID: 1, NAME: \"sample-row\" },\n { ID: 2, NAME: \"second-row\" },\n ],\n columns: [\n { name: \"ID\", typeName: \"INTEGER\" },\n { name: \"NAME\", typeName: \"NVARCHAR\" },\n ],\n affectedRows: 0,\n };\n }\n if (kind === \"dml\") {\n return { rows: [], columns: [], affectedRows: 1 };\n }\n return { rows: [], columns: [], affectedRows: 0 };\n}\n\nfunction fakeExec(sql: string): DriverExecResult {\n const kind = classifyStatement(sql);\n throwForcedFailure(kind);\n const upperSql = sql.toUpperCase();\n throwEarlyFixtureError(upperSql);\n const catalogFixture = matchCatalogFixture(upperSql);\n if (catalogFixture !== undefined) {\n return catalogFixture;\n }\n throwLateFixtureError(upperSql);\n return matchDataFixture(upperSql) ?? defaultResult(kind);\n}\n\n/** Opt-in fake-driver trace; parameter values stay out of test artifacts. */\nasync function traceFakeExec(sql: string, params: readonly SqlParam[]): Promise<void> {\n const tracePath = readEnv(envName(\"FAKE_TRACE_FILE\"));\n if (tracePath === undefined) {\n return;\n }\n const entry = { sql, paramCount: params.length };\n await appendFile(tracePath, `${JSON.stringify(entry)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n}\n\nclass FakeConnection implements DriverConnection {\n private closed = false;\n\n async exec(sql: string, params: readonly SqlParam[]): Promise<DriverExecResult> {\n await traceFakeExec(sql, params);\n return fakeExec(sql);\n }\n\n setAutoCommit(_enabled: boolean): Promise<void> {\n return Promise.resolve();\n }\n\n commit(): Promise<void> {\n return Promise.resolve();\n }\n\n rollback(): Promise<void> {\n return Promise.resolve();\n }\n\n close(): Promise<void> {\n this.closed = true;\n return Promise.resolve();\n }\n\n isClosed(): boolean {\n return this.closed;\n }\n}\n\n/**\n * Opt-in connectivity-failure fixture for the tunnel-fallback E2E suite,\n * mirroring the existing `FAKE_FAIL_STATEMENT` pattern: `\"once\"` fails only\n * the first `connect()` call (every later call in the process succeeds);\n * `\"always\"` fails every call. Unset, `connect()` never fails - identical to\n * today. The thrown error is shaped exactly like a real hdb connectivity\n * failure so it exercises the real classifier, not a generic error.\n */\nfunction maybeFailConnect(): void {\n const mode = readEnv(envName(\"FAKE_FAIL_CONNECT\"));\n if (mode !== \"once\" && mode !== \"always\") {\n return;\n }\n if (mode === \"once\" && connectFailureInjectedOnce) {\n return;\n }\n connectFailureInjectedOnce = true;\n const cause = Object.assign(\n new Error(\"Could not connect to any host: [ fake-host:443 - forced fixture failure ]\"),\n { code: \"EHDBOPENCONN\" },\n );\n throw new CfHanaError(\"CONNECTION\", `Failed to connect to HANA: ${cause.message}`, { cause });\n}\n\n/** Build the deterministic test-only fake HANA driver. */\nexport function createFakeDriver(): HanaDriver {\n return {\n name: \"fake\",\n connect: (_params: DriverConnectParams): Promise<DriverConnection> => {\n maybeFailConnect();\n return Promise.resolve(new FakeConnection());\n },\n };\n}\n","import { createClient } from \"hdb\";\nimport type { HdbClient, HdbColumnMetadata, HdbStatement } from \"hdb\";\n\nimport { CfHanaError, QueryError, databaseCode } from \"../errors.js\";\nimport { quoteIdentifier } from \"../statements.js\";\nimport type { QueryResultColumn, SqlParam } from \"../types.js\";\n\nimport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\nconst TYPE_NAMES: Readonly<Record<number, string>> = {\n 0: \"NULL\",\n 1: \"TINYINT\",\n 2: \"SMALLINT\",\n 3: \"INTEGER\",\n 4: \"BIGINT\",\n 5: \"DECIMAL\",\n 6: \"REAL\",\n 7: \"DOUBLE\",\n 8: \"CHAR\",\n 9: \"VARCHAR\",\n 10: \"NCHAR\",\n 11: \"NVARCHAR\",\n 12: \"BINARY\",\n 13: \"VARBINARY\",\n 14: \"DATE\",\n 15: \"TIME\",\n 16: \"TIMESTAMP\",\n 25: \"CLOB\",\n 26: \"NCLOB\",\n 27: \"BLOB\",\n 28: \"BOOLEAN\",\n 29: \"STRING\",\n 30: \"NSTRING\",\n 47: \"DECIMAL\",\n 51: \"TEXT\",\n 52: \"SHORTTEXT\",\n 62: \"DECIMAL\",\n};\n\nfunction typeName(code: number): string {\n return TYPE_NAMES[code] ?? `TYPE_${String(code)}`;\n}\n\nfunction extractSqlState(error: Error): string | undefined {\n const value = (error as { readonly sqlState?: unknown }).sqlState;\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction toQueryError(error: Error): QueryError {\n const sqlState = extractSqlState(error);\n const code = databaseCode(error);\n return new QueryError(error.message, {\n cause: error,\n ...(sqlState === undefined ? {} : { sqlState }),\n ...(code === undefined ? {} : { databaseCode: code }),\n });\n}\n\nfunction toColumns(\n metadata: readonly HdbColumnMetadata[] | undefined,\n): readonly QueryResultColumn[] {\n if (metadata === undefined) {\n return [];\n }\n return metadata.map((column) => ({\n name: column.columnDisplayName ?? column.columnName ?? \"\",\n typeName: typeName(column.dataType),\n }));\n}\n\nfunction toExecResult(statement: HdbStatement, raw: unknown): DriverExecResult {\n if (typeof raw === \"number\") {\n return { rows: [], columns: [], affectedRows: raw };\n }\n if (Array.isArray(raw)) {\n return {\n rows: raw as readonly Record<string, SqlParam>[],\n columns: toColumns(statement.resultSetMetadata),\n affectedRows: 0,\n };\n }\n return { rows: [], columns: [], affectedRows: 0 };\n}\n\nclass HdbConnection implements DriverConnection {\n private closed = false;\n\n constructor(private readonly client: HdbClient) {}\n\n async exec(sql: string, params: readonly SqlParam[]): Promise<DriverExecResult> {\n const statement = await this.prepareStatement(sql);\n try {\n const raw = await this.executeStatement(statement, params);\n return toExecResult(statement, raw);\n } finally {\n dropStatementQuietly(statement);\n }\n }\n\n setAutoCommit(enabled: boolean): Promise<void> {\n this.client.setAutoCommit(enabled);\n return Promise.resolve();\n }\n\n async commit(): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n this.client.commit((error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n }\n\n async rollback(): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n this.client.rollback((error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return;\n }\n this.closed = true;\n await new Promise<void>((resolve) => {\n this.client.disconnect(() => {\n resolve();\n });\n });\n this.client.close();\n }\n\n isClosed(): boolean {\n return (\n this.closed ||\n this.client.readyState === \"closed\" ||\n this.client.readyState === \"disconnected\"\n );\n }\n\n private async prepareStatement(sql: string): Promise<HdbStatement> {\n return await new Promise<HdbStatement>((resolve, reject) => {\n this.client.prepare(sql, (error, statement) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve(statement);\n }\n });\n });\n }\n\n private async executeStatement(\n statement: HdbStatement,\n params: readonly SqlParam[],\n ): Promise<unknown> {\n return await new Promise<unknown>((resolve, reject) => {\n statement.exec([...params], (error, result) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve(result);\n }\n });\n });\n }\n}\n\nfunction dropStatementQuietly(statement: HdbStatement): void {\n try {\n statement.drop();\n } catch {\n // Best-effort cleanup; preserve the query result or original query error.\n }\n}\n\nfunction openClient(client: HdbClient, timeoutMs: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) {\n return;\n }\n settled = true;\n client.close();\n reject(\n new CfHanaError(\n \"TIMEOUT\",\n `HANA connection timed out after ${String(timeoutMs)}ms`,\n ),\n );\n }, timeoutMs);\n timer.unref();\n client.connect((error) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n if (error) {\n reject(\n new CfHanaError(\"CONNECTION\", `Failed to connect to HANA: ${error.message}`, {\n cause: error,\n }),\n );\n } else {\n resolve();\n }\n });\n });\n}\n\nasync function closeClientQuietly(client: HdbClient): Promise<void> {\n try {\n await new Promise<void>((resolve) => {\n client.disconnect(() => {\n resolve();\n });\n });\n } catch {\n // Best-effort cleanup after a partially opened connection.\n }\n try {\n client.close();\n } catch {\n // Best-effort cleanup after a partially opened connection.\n }\n}\n\nfunction setCurrentSchema(client: HdbClient, schema: string): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n client.exec(`SET SCHEMA ${quoteIdentifier(schema)}`, (error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n}\n\nasync function connectHdb(params: DriverConnectParams): Promise<DriverConnection> {\n const client = createClient({\n host: params.host,\n port: params.port,\n user: params.user,\n password: params.password,\n ca: params.certificate,\n useTLS: true,\n ...(params.servername === undefined ? {} : { servername: params.servername }),\n });\n await openClient(client, params.connectTimeoutMs);\n try {\n await setCurrentSchema(client, params.schema);\n } catch (error) {\n await closeClientQuietly(client);\n throw error;\n }\n return new HdbConnection(client);\n}\n\n/** Build the production HANA driver backed by the pure-JavaScript `hdb` library. */\nexport function createHdbDriver(): HanaDriver {\n return {\n name: \"hdb\",\n connect: connectHdb,\n };\n}\n","import { envName, readEnv } from \"../config.js\";\nimport { CfHanaError } from \"../errors.js\";\n\nimport { createFakeDriver } from \"./fake.js\";\nimport { createHdbDriver } from \"./hdb.js\";\nimport type { HanaDriver } from \"./types.js\";\n\nexport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\n/**\n * Create a HANA driver by name. Defaults to `hdb`; the `CF_HANA_DRIVER`\n * environment variable overrides the default when no name is passed.\n */\nexport function createDriver(name?: string): HanaDriver {\n const resolved = name ?? readEnv(envName(\"DRIVER\")) ?? \"hdb\";\n switch (resolved) {\n case \"hdb\":\n return createHdbDriver();\n case \"fake\":\n return createFakeDriver();\n default:\n throw new CfHanaError(\"CONFIG\", `Unknown HANA driver: ${resolved}`);\n }\n}\n","import { appendFile, mkdir, readdir, rm } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { DbUserRole, StatementKind } from \"./types.js\";\n\nconst SAPTOOLS_DIR_NAME = \".saptools\";\nconst CF_HANA_DIR_NAME = \"cf-hana\";\nconst HISTORIES_DIR_NAME = \"histories\";\nconst HISTORY_RETENTION_DAYS = 5;\nconst HISTORY_FILE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}\\.jsonl$/;\n\nexport type SqlHistoryOperation = \"query\" | \"execute\";\n\nexport interface SqlHistoryEntryInput {\n readonly version: string;\n readonly operation: SqlHistoryOperation;\n readonly selector: string;\n readonly appName: string;\n readonly schema: string;\n readonly role: DbUserRole;\n readonly statement: StatementKind;\n readonly sql: string;\n readonly paramCount: number;\n readonly rowCount: number;\n readonly truncated: boolean;\n readonly elapsedMs: number;\n}\n\nexport interface SqlHistoryEntry extends SqlHistoryEntryInput {\n readonly at: string;\n}\n\nexport interface SqlHistoryWriteOptions {\n readonly now?: Date;\n readonly saptoolsRoot?: string;\n}\n\nfunction defaultSaptoolsRoot(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nfunction padDatePart(value: number): string {\n return value.toString().padStart(2, \"0\");\n}\n\nfunction dateKey(date: Date): string {\n return [\n date.getFullYear().toString(),\n padDatePart(date.getMonth() + 1),\n padDatePart(date.getDate()),\n ].join(\"-\");\n}\n\nfunction retentionCutoffKey(now: Date): string {\n const cutoff = new Date(now);\n cutoff.setHours(0, 0, 0, 0);\n cutoff.setDate(cutoff.getDate() - HISTORY_RETENTION_DAYS);\n return dateKey(cutoff);\n}\n\nfunction resolveSaptoolsRoot(root: string | undefined): string {\n return root ?? defaultSaptoolsRoot();\n}\n\nexport function cfHanaHistoryDirectory(saptoolsRoot?: string): string {\n return join(resolveSaptoolsRoot(saptoolsRoot), CF_HANA_DIR_NAME, HISTORIES_DIR_NAME);\n}\n\nexport function sqlHistoryFilePath(now: Date = new Date(), saptoolsRoot?: string): string {\n return join(cfHanaHistoryDirectory(saptoolsRoot), `${dateKey(now)}.jsonl`);\n}\n\nasync function pruneSqlHistory(now: Date, saptoolsRoot?: string): Promise<void> {\n const historyDir = cfHanaHistoryDirectory(saptoolsRoot);\n let files: readonly string[];\n try {\n files = await readdir(historyDir);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n\n const cutoffKey = retentionCutoffKey(now);\n await Promise.all(\n files\n .filter((file) => HISTORY_FILE_PATTERN.test(file))\n .filter((file) => file.slice(0, 10) < cutoffKey)\n .map(async (file) => {\n await rm(join(historyDir, file), { force: true });\n }),\n );\n}\n\nexport async function appendSqlHistory(\n input: SqlHistoryEntryInput,\n options: SqlHistoryWriteOptions = {},\n): Promise<SqlHistoryEntry> {\n const now = options.now ?? new Date();\n const historyDir = cfHanaHistoryDirectory(options.saptoolsRoot);\n const entry: SqlHistoryEntry = {\n at: now.toISOString(),\n ...input,\n };\n\n await mkdir(historyDir, { recursive: true, mode: 0o700 });\n await appendFile(sqlHistoryFilePath(now, options.saptoolsRoot), `${JSON.stringify(entry)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n try {\n await pruneSqlHistory(now, options.saptoolsRoot);\n } catch {\n // Retention is best-effort; the SQL history entry was already recorded.\n }\n\n return entry;\n}\n","import { classifyStatement, firstKeyword } from \"./statements.js\";\nimport type { StatementKind } from \"./types.js\";\n\nconst DESTRUCTIVE_DDL_KEYWORDS = new Set([\"DROP\", \"TRUNCATE\", \"ALTER\"]);\nconst UNSCOPED_WRITE_KEYWORDS = new Set([\"UPDATE\", \"DELETE\"]);\n\nexport type GuardViolation = \"read-only\" | \"destructive\";\n\nexport interface GuardConfig {\n readonly readOnly: boolean;\n readonly allowDestructive: boolean;\n}\n\nexport interface GuardDecision {\n readonly allowed: boolean;\n readonly destructive: boolean;\n readonly violation: GuardViolation | undefined;\n readonly reason: string | undefined;\n}\n\nexport interface StatementInspection {\n readonly kind: StatementKind;\n readonly destructive: boolean;\n}\n\nexport interface AutoLimitResult {\n readonly sql: string;\n readonly applied: boolean;\n readonly requestedLimit?: number;\n}\n\nfunction skipQuotedText(sql: string, start: number): number {\n const quote = sql[start];\n let index = start + 1;\n while (index < sql.length) {\n if (sql[index] === quote) {\n if (sql[index + 1] === quote) {\n index += 2;\n continue;\n }\n index += 1;\n break;\n }\n index += 1;\n }\n return index;\n}\n\nfunction skipLineComment(sql: string, start: number): number {\n let index = start + 2;\n while (index < sql.length && sql[index] !== \"\\n\") {\n index += 1;\n }\n return index;\n}\n\nfunction skipBlockComment(sql: string, start: number): number {\n let index = start + 2;\n while (index < sql.length && !(sql[index] === \"*\" && sql[index + 1] === \"/\")) {\n index += 1;\n }\n return Math.min(index + 2, sql.length);\n}\n\nfunction maskIgnoredSqlText(sql: string): string {\n let masked = \"\";\n let index = 0;\n while (index < sql.length) {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n const end = skipQuotedText(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n const end = skipLineComment(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n const end = skipBlockComment(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n masked += char ?? \"\";\n index += 1;\n }\n return masked;\n}\n\nfunction hasTopLevelKeyword(sql: string, keyword: string): boolean {\n const masked = maskIgnoredSqlText(sql);\n let depth = 0;\n for (let index = 0; index < masked.length; index += 1) {\n const char = masked[index];\n if (char === \"(\") {\n depth += 1;\n continue;\n }\n if (char === \")\") {\n depth = Math.max(0, depth - 1);\n continue;\n }\n if (\n depth === 0 &&\n masked.slice(index, index + keyword.length).toUpperCase() === keyword &&\n !/[A-Za-z0-9_$#]/.test(masked.charAt(index - 1)) &&\n !/[A-Za-z0-9_$#]/.test(masked.charAt(index + keyword.length))\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction isUnconditionalMergeDelete(sql: string): boolean {\n return /\\bWHEN\\s+MATCHED\\s+THEN\\s+DELETE\\b/i.test(maskIgnoredSqlText(sql));\n}\n\nfunction isMalformedReplace(sql: string): boolean {\n return (\n !hasTopLevelKeyword(sql, \"VALUES\") &&\n !hasTopLevelKeyword(sql, \"SELECT\") &&\n !hasTopLevelKeyword(sql, \"WITH\")\n );\n}\n\nfunction trailingLineCommentIndex(sql: string): number | undefined {\n let index = 0;\n while (index < sql.length) {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n index = skipQuotedText(sql, index);\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n index = skipBlockComment(sql, index);\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n const lineEnd = sql.indexOf(\"\\n\", index + 2);\n if (lineEnd === -1 || sql.slice(lineEnd + 1).trim().length === 0) {\n return index;\n }\n index = lineEnd + 1;\n continue;\n }\n index += 1;\n }\n return undefined;\n}\n\nfunction appendLimit(sql: string, limit: number): string {\n const trimmed = sql.replace(/(?<![\\s;])[\\s;]+$/, \"\");\n const commentIndex = trailingLineCommentIndex(trimmed);\n if (commentIndex === undefined) {\n return `${trimmed} LIMIT ${String(limit)}`;\n }\n const beforeComment = trimmed.slice(0, commentIndex).replace(/(?<![\\s;])[\\s;]+$/, \"\");\n const comment = trimmed.slice(commentIndex);\n return `${beforeComment} LIMIT ${String(limit)} ${comment}`;\n}\n\n/** Inspect a statement's kind and whether it is destructive. */\nexport function inspectStatement(sql: string): StatementInspection {\n const kind = classifyStatement(sql);\n const keyword = firstKeyword(sql);\n if (kind === \"ddl\") {\n return { kind, destructive: DESTRUCTIVE_DDL_KEYWORDS.has(keyword) };\n }\n if (kind === \"dml\") {\n const destructive =\n (UNSCOPED_WRITE_KEYWORDS.has(keyword) && !hasTopLevelKeyword(sql, \"WHERE\")) ||\n (keyword === \"MERGE\" && isUnconditionalMergeDelete(sql)) ||\n (keyword === \"REPLACE\" && isMalformedReplace(sql));\n return {\n kind,\n destructive,\n };\n }\n return { kind, destructive: false };\n}\n\n/** Decide whether a statement may run under the given safety configuration. */\nexport function evaluateGuard(sql: string, config: GuardConfig): GuardDecision {\n const inspection = inspectStatement(sql);\n\n if (config.readOnly && inspection.kind !== \"select\") {\n return {\n allowed: false,\n destructive: inspection.destructive,\n violation: \"read-only\",\n reason:\n inspection.kind === \"unknown\"\n ? \"read-only mode only permits SELECT/WITH statements\"\n : `read-only mode blocks ${inspection.kind.toUpperCase()} statements`,\n };\n }\n\n if (inspection.destructive && !config.allowDestructive) {\n return {\n allowed: false,\n destructive: true,\n violation: \"destructive\",\n reason:\n \"destructive statement blocked (DROP/TRUNCATE/ALTER, unscoped UPDATE/DELETE, \" +\n \"or unconditional matched MERGE DELETE); \" +\n \"allow it explicitly to proceed\",\n };\n }\n\n return {\n allowed: true,\n destructive: inspection.destructive,\n violation: undefined,\n reason: undefined,\n };\n}\n\n/** Append a `LIMIT` clause to a bare SELECT that has no row cap of its own. */\nexport function applyAutoLimit(sql: string, limit: number | false): AutoLimitResult {\n if (limit === false || classifyStatement(sql) !== \"select\") {\n return { sql, applied: false };\n }\n\n const stripped = maskIgnoredSqlText(sql);\n if (/\\blimit\\b/i.test(stripped) || /\\btop\\s+\\d/i.test(stripped)) {\n return { sql, applied: false };\n }\n\n return {\n sql: appendLimit(sql, limit + 1),\n applied: true,\n requestedLimit: limit,\n };\n}\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { DEFAULT_TUNNEL_FALLBACK_BUDGET_MS } from \"../config.js\";\n\nimport { killTunnelProcess, probeLocalPort } from \"./process.js\";\n\nconst DEFAULT_ESTABLISHING_STALE_MS = 2 * DEFAULT_TUNNEL_FALLBACK_BUDGET_MS;\nconst DEFAULT_POLL_INTERVAL_MS = 300;\n\nexport interface TunnelOrgKey {\n readonly apiEndpoint: string;\n readonly orgName: string;\n}\n\nexport interface TunnelEstablishingRecord {\n readonly version: 1;\n readonly status: \"establishing\";\n readonly host: string;\n readonly startedAt: string;\n readonly ownerPid: number;\n readonly orgKey: TunnelOrgKey;\n}\n\nexport interface TunnelReadyRecord {\n readonly version: 1;\n readonly status: \"ready\";\n readonly host: string;\n readonly localPort: number;\n readonly pid: number;\n readonly app: string;\n readonly orgKey: TunnelOrgKey;\n readonly expiresAt: string;\n}\n\nexport type TunnelCacheRecord = TunnelEstablishingRecord | TunnelReadyRecord;\n\nexport type ClaimResult =\n | { readonly outcome: \"claimed\" }\n | { readonly outcome: \"already-ready\"; readonly record: TunnelReadyRecord }\n | { readonly outcome: \"wait\" };\n\nexport interface TunnelCacheOptions {\n readonly saptoolsRoot?: string;\n readonly now?: () => Date;\n readonly isProcessAlive?: (pid: number) => boolean;\n readonly probePort?: (port: number) => Promise<boolean>;\n readonly killProcess?: (pid: number | undefined) => void;\n /** How long an establishing marker may exist before an alive owner is presumed hung. */\n readonly staleAfterMs?: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction defaultIsProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n // ESRCH means the process is genuinely gone; any other outcome (e.g.\n // EPERM for a process owned by another user) means it still exists.\n return isRecord(error) && error[\"code\"] !== \"ESRCH\";\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nfunction tunnelCacheRoot(saptoolsRoot?: string): string {\n return join(saptoolsRoot ?? join(homedir(), \".saptools\"), \"cf-hana\", \"tunnel\");\n}\n\nexport function tunnelCacheKey(host: string): string {\n return createHash(\"sha256\").update(host).digest(\"hex\");\n}\n\nfunction tunnelCachePath(host: string, saptoolsRoot?: string): string {\n return join(tunnelCacheRoot(saptoolsRoot), `${tunnelCacheKey(host)}.json`);\n}\n\nfunction isOrgKey(value: unknown): value is TunnelOrgKey {\n return (\n isRecord(value) &&\n typeof value[\"apiEndpoint\"] === \"string\" &&\n typeof value[\"orgName\"] === \"string\"\n );\n}\n\nfunction hasEstablishingFields(value: Record<string, unknown>): boolean {\n return (\n value[\"status\"] === \"establishing\" &&\n typeof value[\"host\"] === \"string\" &&\n typeof value[\"startedAt\"] === \"string\" &&\n typeof value[\"ownerPid\"] === \"number\" &&\n isOrgKey(value[\"orgKey\"])\n );\n}\n\nfunction hasReadyFields(value: Record<string, unknown>): boolean {\n return (\n value[\"status\"] === \"ready\" &&\n typeof value[\"host\"] === \"string\" &&\n typeof value[\"localPort\"] === \"number\" &&\n typeof value[\"pid\"] === \"number\" &&\n typeof value[\"app\"] === \"string\" &&\n typeof value[\"expiresAt\"] === \"string\" &&\n isOrgKey(value[\"orgKey\"])\n );\n}\n\nfunction isTunnelCacheRecord(value: unknown): value is TunnelCacheRecord {\n return (\n isRecord(value) &&\n value[\"version\"] === 1 &&\n (hasEstablishingFields(value) || hasReadyFields(value))\n );\n}\n\nasync function parseTunnelCacheFile(path: string): Promise<TunnelCacheRecord | undefined> {\n try {\n const raw: unknown = JSON.parse(await readFile(path, \"utf8\"));\n return isTunnelCacheRecord(raw) ? raw : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Read the current cache entry for a host, or `undefined` if absent/malformed. */\nexport async function readTunnelCacheEntry(\n host: string,\n options: TunnelCacheOptions = {},\n): Promise<TunnelCacheRecord | undefined> {\n const entry = await parseTunnelCacheFile(tunnelCachePath(host, options.saptoolsRoot));\n return entry?.host === host ? entry : undefined;\n}\n\nfunction isExpired(entry: TunnelReadyRecord, now: Date): boolean {\n const expiresAt = Date.parse(entry.expiresAt);\n return !Number.isFinite(expiresAt) || now.getTime() >= expiresAt;\n}\n\n/**\n * The thorough reuse check: pid alive, local port still accepting\n * connections, and not past its recorded expiry. A local forward's listener\n * can outlive a dead remote SSH leg, so none of these alone is sufficient.\n */\nexport async function isTunnelUsable(\n entry: TunnelReadyRecord,\n options: TunnelCacheOptions = {},\n): Promise<boolean> {\n const isAlive = options.isProcessAlive ?? defaultIsProcessAlive;\n if (!isAlive(entry.pid)) {\n return false;\n }\n if (isExpired(entry, options.now?.() ?? new Date())) {\n return false;\n }\n const probePort = options.probePort ?? probeLocalPort;\n return await probePort(entry.localPort);\n}\n\nfunction isEstablishingStale(entry: TunnelEstablishingRecord, options: TunnelCacheOptions): boolean {\n const isAlive = options.isProcessAlive ?? defaultIsProcessAlive;\n if (!isAlive(entry.ownerPid)) {\n return true;\n }\n const startedAt = Date.parse(entry.startedAt);\n if (!Number.isFinite(startedAt)) {\n return true;\n }\n const now = options.now?.() ?? new Date();\n const staleAfterMs = options.staleAfterMs ?? DEFAULT_ESTABLISHING_STALE_MS;\n return now.getTime() - startedAt >= staleAfterMs;\n}\n\nasync function writeEstablishingMarker(\n host: string,\n ownerPid: number,\n orgKey: TunnelOrgKey,\n options: TunnelCacheOptions,\n): Promise<boolean> {\n const root = tunnelCacheRoot(options.saptoolsRoot);\n await mkdir(root, { recursive: true, mode: 0o700 });\n const record: TunnelEstablishingRecord = {\n version: 1,\n status: \"establishing\",\n host,\n startedAt: (options.now?.() ?? new Date()).toISOString(),\n ownerPid,\n orgKey,\n };\n try {\n await writeFile(tunnelCachePath(host, options.saptoolsRoot), `${JSON.stringify(record)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n flag: \"wx\",\n });\n return true;\n } catch (error) {\n if (isRecord(error) && error[\"code\"] === \"EEXIST\") {\n return false;\n }\n throw error;\n }\n}\n\n/**\n * Attempts to become the sole establisher for a host. Exclusive file\n * creation is the only real \"who goes first\" signal — a plain temp-then-\n * rename write (as the existing metadata cache uses) cannot resolve two\n * processes racing to establish the same host's tunnel.\n */\nexport async function claimEstablishing(\n host: string,\n ownerPid: number,\n orgKey: TunnelOrgKey,\n options: TunnelCacheOptions = {},\n): Promise<ClaimResult> {\n if (await writeEstablishingMarker(host, ownerPid, orgKey, options)) {\n return { outcome: \"claimed\" };\n }\n const existing = await readTunnelCacheEntry(host, options);\n if (existing === undefined) {\n // Disappeared between our failed create and this read (the previous\n // owner just finalized as failed) - the slot is free again.\n return (await writeEstablishingMarker(host, ownerPid, orgKey, options))\n ? { outcome: \"claimed\" }\n : { outcome: \"wait\" };\n }\n if (existing.status === \"ready\") {\n return { outcome: \"already-ready\", record: existing };\n }\n if (!isEstablishingStale(existing, options)) {\n return { outcome: \"wait\" };\n }\n await rm(tunnelCachePath(host, options.saptoolsRoot), { force: true });\n // The takeover still ends in the same exclusive create; if another\n // process wins this tiny remove-then-recreate window, back off and let\n // the caller poll rather than looping to retry the takeover itself.\n return (await writeEstablishingMarker(host, ownerPid, orgKey, options))\n ? { outcome: \"claimed\" }\n : { outcome: \"wait\" };\n}\n\n/** Polls for the current owner's outcome: the ready record, or `undefined` on failure/timeout. */\nexport async function waitForEstablishment(\n host: string,\n deadline: number,\n pollIntervalMs: number = DEFAULT_POLL_INTERVAL_MS,\n options: TunnelCacheOptions = {},\n): Promise<TunnelReadyRecord | undefined> {\n for (;;) {\n const entry = await readTunnelCacheEntry(host, options);\n if (entry === undefined) {\n return undefined;\n }\n if (entry.status === \"ready\") {\n return entry;\n }\n const remainingMs = deadline - Date.now();\n if (remainingMs <= 0) {\n return undefined;\n }\n await sleep(Math.min(pollIntervalMs, remainingMs));\n }\n}\n\n/** The winning establisher's success path: atomic write, replacing the marker. */\nexport async function finalizeEstablishingReady(\n host: string,\n record: Omit<TunnelReadyRecord, \"version\" | \"status\" | \"host\">,\n options: TunnelCacheOptions = {},\n): Promise<void> {\n const root = tunnelCacheRoot(options.saptoolsRoot);\n const path = tunnelCachePath(host, options.saptoolsRoot);\n const tempPath = `${path}.tmp-${String(process.pid)}`;\n const stored: TunnelReadyRecord = { version: 1, status: \"ready\", host, ...record };\n await mkdir(root, { recursive: true, mode: 0o700 });\n await rm(tempPath, { force: true });\n await writeFile(tempPath, `${JSON.stringify(stored)}\\n`, { encoding: \"utf8\", mode: 0o600 });\n await rename(tempPath, path);\n}\n\n/**\n * The winning establisher's clean-failure path: the marker is removed\n * entirely, never left in place - a stranded `establishing` record would\n * force every waiter to burn its own budget for no reason.\n */\nexport async function finalizeEstablishingFailed(\n host: string,\n options: TunnelCacheOptions = {},\n): Promise<void> {\n await rm(tunnelCachePath(host, options.saptoolsRoot), { force: true });\n}\n\n/** Discards a cache entry outright (self-healing after a reuse attempt fails). */\nexport async function evictTunnelCache(\n host: string,\n options: TunnelCacheOptions = {},\n): Promise<void> {\n await rm(tunnelCachePath(host, options.saptoolsRoot), { force: true });\n}\n\nfunction sameOrg(a: TunnelOrgKey, b: TunnelOrgKey): boolean {\n return a.apiEndpoint === b.apiEndpoint && a.orgName === b.orgName;\n}\n\nasync function reapOneFile(\n path: string,\n currentOrgKey: TunnelOrgKey,\n options: TunnelCacheOptions,\n): Promise<void> {\n const entry = await parseTunnelCacheFile(path);\n if (entry === undefined) {\n return;\n }\n const killProcess = options.killProcess ?? killTunnelProcess;\n if (entry.status === \"establishing\") {\n if (isEstablishingStale(entry, options)) {\n await rm(path, { force: true });\n }\n // A live, non-stale establishing marker is left alone regardless of\n // org: establishment is transient and will resolve on its own, and\n // reaping it here could destroy a different process's in-flight work.\n return;\n }\n const isAlive = options.isProcessAlive ?? defaultIsProcessAlive;\n if (!isAlive(entry.pid)) {\n await rm(path, { force: true });\n return;\n }\n const now = options.now?.() ?? new Date();\n if (isExpired(entry, now) || !sameOrg(entry.orgKey, currentOrgKey)) {\n killProcess(entry.pid);\n await rm(path, { force: true });\n }\n}\n\n/**\n * Cheap pass (pid liveness + expiry only, no TCP probe) run on every\n * `Connection.open()`: reaps dead entries of either status, reaps an alive\n * but age-stale establishing marker, and closes a live `ready` tunnel the\n * moment it is expired or tagged for a different org than this invocation\n * is currently targeting - regardless of its remaining TTL, so a different\n * client's landscape never has an unattended live SSH path left open.\n */\nexport async function reapStaleAndCrossOrgTunnels(\n currentOrgKey: TunnelOrgKey,\n options: TunnelCacheOptions = {},\n): Promise<void> {\n const root = tunnelCacheRoot(options.saptoolsRoot);\n let files: readonly string[];\n try {\n files = await readdir(root);\n } catch {\n return;\n }\n await Promise.all(\n files\n .filter((file) => file.endsWith(\".json\"))\n .map(async (file) => {\n await reapOneFile(join(root, file), currentOrgKey, options);\n }),\n );\n}\n","import { spawn } from \"node:child_process\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { connect as netConnect, createServer } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { cfApi, cfAuth, cfTargetSpace, resolveCfBin } from \"../cf.js\";\nimport type { CfExecContext } from \"../cf.js\";\nimport type { SapCredentials } from \"../config.js\";\nimport { CfHanaError, CredentialsNotFoundError } from \"../errors.js\";\nimport type { SelectorSource } from \"../types.js\";\n\nconst PORT_POLL_INTERVAL_MS = 100;\nconst DEFAULT_PORT_PROBE_TIMEOUT_MS = 500;\n\nexport interface TunnelTarget {\n readonly apiEndpoint: string;\n readonly orgName: string;\n readonly spaceName: string;\n}\n\nexport interface TunnelChildProcess {\n readonly pid: number | undefined;\n on(event: \"exit\" | \"error\", listener: (...args: readonly unknown[]) => void): void;\n removeListener(event: \"exit\" | \"error\", listener: (...args: readonly unknown[]) => void): void;\n unref(): void;\n}\n\nexport type SpawnTunnelProcessFn = (\n command: string,\n args: readonly string[],\n options: { readonly detached: true; readonly stdio: \"ignore\"; readonly env: NodeJS.ProcessEnv },\n) => TunnelChildProcess;\n\nexport interface SpawnTunnelParams {\n readonly cfHome: string | undefined;\n readonly app: string;\n readonly hanaHost: string;\n readonly hanaPort: number;\n readonly keepaliveSeconds: number;\n /** Absolute `Date.now()`-comparable wall-clock cutoff shared across every candidate. */\n readonly deadline: number;\n /** Secondary per-candidate ceiling; the remaining shared deadline still wins if smaller. */\n readonly candidateTimeoutMs: number;\n}\n\nexport interface SpawnTunnelResult {\n readonly localPort: number;\n readonly pid: number;\n}\n\nexport interface SpawnTunnelDeps {\n readonly spawnProcess?: SpawnTunnelProcessFn;\n readonly probePort?: (port: number) => Promise<boolean>;\n readonly allocatePort?: () => Promise<number>;\n readonly killProcess?: (pid: number | undefined) => void;\n}\n\nfunction assertPositiveSafeInteger(label: string, value: number): void {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new CfHanaError(\"CONFIG\", `${label} must be a positive integer`);\n }\n}\n\n/** Ephemeral local TCP port: bound then released for a spawned listener to reclaim. */\nexport async function allocateLocalPort(): Promise<number> {\n return await new Promise<number>((resolve, reject) => {\n const server = createServer();\n server.once(\"error\", reject);\n server.listen(0, \"127.0.0.1\", () => {\n const address = server.address();\n server.close(() => {\n if (address === null || typeof address === \"string\") {\n reject(new CfHanaError(\"CONNECTION\", \"Could not allocate a local port for a tunnel\"));\n return;\n }\n resolve(address.port);\n });\n });\n });\n}\n\n/** True once a TCP connection to `127.0.0.1:<port>` succeeds; bounded by a short timeout. */\nexport function probeLocalPort(\n port: number,\n timeoutMs: number = DEFAULT_PORT_PROBE_TIMEOUT_MS,\n): Promise<boolean> {\n return new Promise((resolve) => {\n let settled = false;\n const socket = netConnect({ host: \"127.0.0.1\", port });\n const finish = (result: boolean): void => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n socket.destroy();\n resolve(result);\n };\n const timer = setTimeout(() => {\n finish(false);\n }, timeoutMs);\n timer.unref();\n socket.once(\"connect\", () => {\n finish(true);\n });\n socket.once(\"error\", () => {\n finish(false);\n });\n });\n}\n\n/** Best-effort termination of an abandoned candidate's tunnel process. */\nexport function killTunnelProcess(pid: number | undefined): void {\n if (pid === undefined) {\n return;\n }\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {\n // Already exited or inaccessible; nothing more to do.\n }\n}\n\n/**\n * Runs `work` with the CF execution context appropriate for the selector\n * source: `undefined` (ambient env, no override — mirrors `cfEnvDirect`) for\n * an ambient selector, or a fresh, isolated `CF_HOME` authenticated against\n * the resolved org/space for an explicit selector. Unlike `withCfSession`,\n * cleanup of the isolated `CF_HOME` is deferred until `work`'s returned\n * promise settles rather than run synchronously the instant a callback\n * returns — required because `work` here spawns a detached process expected\n * to keep running after this function returns.\n */\nexport async function withScopedCfSession<T>(\n selectorSource: SelectorSource,\n target: TunnelTarget,\n sapCredentials: SapCredentials | undefined,\n work: (ctx?: CfExecContext) => Promise<T>,\n): Promise<T> {\n if (selectorSource === \"ambient\") {\n return await work();\n }\n if (sapCredentials === undefined) {\n throw new CredentialsNotFoundError(\n \"SAP credentials are required to open a tunnel session for an explicit selector\",\n );\n }\n const cfHome = await mkdtemp(join(tmpdir(), \"saptools-cf-hana-tunnel-\"));\n try {\n const ctx: CfExecContext = { cfHome };\n await cfApi(target.apiEndpoint, ctx);\n await cfAuth(sapCredentials.email, sapCredentials.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n return await work(ctx);\n } finally {\n await rm(cfHome, { recursive: true, force: true });\n }\n}\n\nfunction raceTunnelReadiness(\n child: TunnelChildProcess,\n localPort: number,\n boundMs: number,\n probePort: (port: number) => Promise<boolean>,\n killProcess: (pid: number | undefined) => void,\n): Promise<SpawnTunnelResult | undefined> {\n return new Promise((resolve) => {\n let settled = false;\n const timers: { poll?: NodeJS.Timeout; deadline?: NodeJS.Timeout } = {};\n\n const finish = (result?: SpawnTunnelResult): void => {\n if (settled) {\n return;\n }\n settled = true;\n clearInterval(timers.poll);\n clearTimeout(timers.deadline);\n child.removeListener(\"exit\", onAbort);\n child.removeListener(\"error\", onAbort);\n if (result === undefined) {\n killProcess(child.pid);\n } else {\n child.unref();\n }\n resolve(result);\n };\n\n function onAbort(): void {\n finish();\n }\n\n // Attached synchronously, with no `await` since `spawn()` returned:\n // child_process.spawn reports a missing/unexecutable binary via an\n // async 'error' event, not a synchronous throw, and an EventEmitter\n // 'error' event with no listener throws uncaught.\n child.on(\"exit\", onAbort);\n child.on(\"error\", onAbort);\n\n timers.poll = setInterval(() => {\n void probePort(localPort).then((open) => {\n if (open && child.pid !== undefined) {\n finish({ localPort, pid: child.pid });\n }\n });\n }, PORT_POLL_INTERVAL_MS);\n\n timers.deadline = setTimeout(finish, boundMs);\n });\n}\n\n/**\n * Spawns a detached `cf ssh -L` forward and races \"the local port becomes\n * connectable\" against \"the process exited/errored early\" against the\n * remaining shared fallback deadline. Returns `undefined` on any failure —\n * the caller tries the next candidate, or gives up once the deadline is\n * spent. Never throws for a failed candidate; only configuration errors\n * (an invalid keepalive value) throw before anything is spawned.\n */\nexport async function spawnTunnel(\n params: SpawnTunnelParams,\n deps: SpawnTunnelDeps = {},\n): Promise<SpawnTunnelResult | undefined> {\n assertPositiveSafeInteger(\"tunnel keepalive seconds\", params.keepaliveSeconds);\n const remainingMs = params.deadline - Date.now();\n if (remainingMs <= 0) {\n return undefined;\n }\n const boundMs = Math.min(remainingMs, params.candidateTimeoutMs);\n const spawnProcess = deps.spawnProcess ?? (spawn as unknown as SpawnTunnelProcessFn);\n const probePort = deps.probePort ?? probeLocalPort;\n const allocatePort = deps.allocatePort ?? allocateLocalPort;\n const killProcess = deps.killProcess ?? killTunnelProcess;\n\n const localPort = await allocatePort();\n const { bin, argsPrefix } = resolveCfBin();\n const forward = `${String(localPort)}:${params.hanaHost}:${String(params.hanaPort)}`;\n const args = [\n ...argsPrefix,\n \"ssh\",\n params.app,\n \"-L\",\n forward,\n \"-c\",\n `sleep ${String(params.keepaliveSeconds)}`,\n ];\n const env: NodeJS.ProcessEnv =\n params.cfHome === undefined ? { ...process.env } : { ...process.env, CF_HOME: params.cfHome };\n const child = spawnProcess(bin, args, { detached: true, stdio: \"ignore\", env });\n\n return await raceTunnelReadiness(child, localPort, boundMs, probePort, killProcess);\n}\n","import { parseCfAppsOutput } from \"../cf.js\";\n\nconst RUNNING_STATE = \"started\";\nconst VALID_APP_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\n\nfunction isValidAppName(name: string): boolean {\n return VALID_APP_NAME.test(name);\n}\n\nfunction discoveredAppNames(stdout: string | undefined, targetAppName: string): readonly string[] {\n if (stdout === undefined) {\n return [];\n }\n const seen = new Set<string>();\n const names: string[] = [];\n for (const row of parseCfAppsOutput(stdout)) {\n if (row.state !== RUNNING_STATE) {\n continue;\n }\n if (row.name === targetAppName || seen.has(row.name)) {\n continue;\n }\n if (!isValidAppName(row.name)) {\n continue;\n }\n seen.add(row.name);\n names.push(row.name);\n }\n return names;\n}\n\n/**\n * Orders jump-host candidates: the target app first (it is already a known,\n * resolved CF app, and its own container is the natural first guess), then\n * up to `maxCandidates` other started apps discovered via `cf apps`, deduped\n * and shape-validated so a CF API response can never smuggle an extra flag\n * or shell-adjacent token into a later spawn call.\n */\nexport function buildCandidateList(\n targetAppName: string,\n discoveredStdout: string | undefined,\n maxCandidates: number,\n): readonly string[] {\n const discovered = discoveredAppNames(discoveredStdout, targetAppName);\n return [targetAppName, ...discovered.slice(0, maxCandidates)];\n}\n","import { CfHanaError } from \"../errors.js\";\n\nconst CONNECT_TIMEOUT_MESSAGE = \"HANA connection timed out\";\nconst OPEN_CONNECTION_CODE = \"EHDBOPENCONN\";\nconst MAX_CAUSE_DEPTH = 5;\n\nfunction causeCode(value: unknown): unknown {\n return typeof value === \"object\" && value !== null\n ? (value as { readonly code?: unknown }).code\n : undefined;\n}\n\nfunction causeOf(value: unknown): unknown {\n return typeof value === \"object\" && value !== null\n ? (value as { readonly cause?: unknown }).cause\n : undefined;\n}\n\nfunction hasOpenConnectionCause(cause: unknown, depth: number): boolean {\n if (depth > MAX_CAUSE_DEPTH) {\n return false;\n }\n if (causeCode(cause) === OPEN_CONNECTION_CODE) {\n return true;\n }\n return hasOpenConnectionCause(causeOf(cause), depth + 1);\n}\n\n/**\n * True only for a failure to establish the initial HANA socket — never for\n * an authentication, privilege, or query failure (all reached structurally\n * after a socket already opened), and never for the unrelated query-phase\n * timeout that shares the same `TIMEOUT` code as the connect-phase one.\n */\nexport function isConnectivityFailure(error: unknown): boolean {\n if (!(error instanceof CfHanaError)) {\n return false;\n }\n if (error.code === \"TIMEOUT\") {\n return error.message.includes(CONNECT_TIMEOUT_MESSAGE);\n }\n if (error.code !== \"CONNECTION\") {\n return false;\n }\n return hasOpenConnectionCause(error.cause, 0);\n}\n","import * as cf from \"../cf.js\";\nimport type { CfExecContext } from \"../cf.js\";\nimport {\n DEFAULT_TUNNEL_CANDIDATE_TIMEOUT_MS,\n DEFAULT_TUNNEL_FALLBACK_BUDGET_MS,\n DEFAULT_TUNNEL_KEEPALIVE_SECONDS,\n DEFAULT_TUNNEL_MAX_CANDIDATES,\n} from \"../config.js\";\nimport type { SapCredentials } from \"../config.js\";\nimport type { DriverConnectParams, DriverConnection, HanaDriver } from \"../driver/types.js\";\nimport { CfHanaError } from \"../errors.js\";\nimport type { SelectorSource } from \"../types.js\";\n\nimport {\n claimEstablishing,\n evictTunnelCache,\n finalizeEstablishingFailed,\n finalizeEstablishingReady,\n isTunnelUsable,\n reapStaleAndCrossOrgTunnels,\n readTunnelCacheEntry,\n waitForEstablishment,\n} from \"./cache.js\";\nimport type { TunnelCacheOptions, TunnelOrgKey, TunnelReadyRecord } from \"./cache.js\";\nimport { buildCandidateList } from \"./candidates.js\";\nimport { isConnectivityFailure } from \"./classifier.js\";\nimport {\n killTunnelProcess,\n spawnTunnel,\n withScopedCfSession,\n} from \"./process.js\";\nimport type { SpawnTunnelDeps, SpawnTunnelResult } from \"./process.js\";\n\n/**\n * Everything `connectWithTunnelFallback` needs from `ConnectionConfig`,\n * declared locally rather than imported from `../connection.js` — that\n * module calls this one, and importing `ConnectionConfig` back from it\n * would create an import cycle. Kept structurally identical to (a subset\n * of) `ConnectionConfig` so callers pass their config object unchanged.\n */\nexport interface TunnelFallbackConfig {\n readonly host: string;\n readonly port: number;\n readonly user: string;\n readonly password: string;\n readonly schema: string;\n readonly certificate: string;\n readonly connectTimeoutMs: number;\n readonly appName: string;\n readonly orgName: string;\n readonly spaceName: string;\n readonly apiEndpoint: string;\n readonly selectorSource: SelectorSource;\n readonly tunnelMode: \"auto\" | \"always\";\n readonly refreshTunnel: boolean;\n readonly sapCredentials?: SapCredentials;\n readonly onTunnelStatus?: (message: string) => void;\n}\n\nexport interface TunnelFallbackOverrides {\n readonly cache?: TunnelCacheOptions;\n readonly process?: SpawnTunnelDeps;\n}\n\nconst EXPIRY_SAFETY_MARGIN_MS = 30_000;\n\nfunction directParamsOf(config: TunnelFallbackConfig): DriverConnectParams {\n return {\n host: config.host,\n port: config.port,\n user: config.user,\n password: config.password,\n schema: config.schema,\n certificate: config.certificate,\n connectTimeoutMs: config.connectTimeoutMs,\n };\n}\n\nfunction tunneledParams(directParams: DriverConnectParams, localPort: number): DriverConnectParams {\n return { ...directParams, host: \"127.0.0.1\", port: localPort, servername: directParams.host };\n}\n\nfunction orgKeyOf(config: TunnelFallbackConfig): TunnelOrgKey {\n return { apiEndpoint: config.apiEndpoint, orgName: config.orgName };\n}\n\nfunction tunnelExpiryIso(): string {\n return new Date(\n Date.now() + DEFAULT_TUNNEL_KEEPALIVE_SECONDS * 1000 - EXPIRY_SAFETY_MARGIN_MS,\n ).toISOString();\n}\n\nasync function discardQuietly(work: Promise<unknown>): Promise<void> {\n await work.catch(() => {\n // Best-effort cache/cleanup write; never let it block a connection.\n });\n}\n\n/**\n * Connects through an already-known-ready tunnel record. A bare TCP-connect\n * success on an SSH local forward does not prove the remote leg is still\n * alive, so a connectivity-shaped failure here evicts the entry and reports\n * \"no usable cache\" rather than surfacing the error - the caller falls\n * through to fresh discovery. A non-connectivity failure proves the tunnel\n * itself works, so it is left cached and the error is rethrown unchanged.\n */\nasync function tryReadyRecord(\n record: TunnelReadyRecord,\n driver: HanaDriver,\n config: TunnelFallbackConfig,\n directParams: DriverConnectParams,\n cacheOptions: TunnelCacheOptions,\n): Promise<DriverConnection | undefined> {\n try {\n const connection = await driver.connect(tunneledParams(directParams, record.localPort));\n config.onTunnelStatus?.(`connected via SSH tunnel through ${record.app}`);\n return connection;\n } catch (error) {\n if (isConnectivityFailure(error)) {\n await discardQuietly(evictTunnelCache(config.host, cacheOptions));\n return undefined;\n }\n throw error;\n }\n}\n\nasync function discoverAppsStdout(ctx: CfExecContext | undefined): Promise<string | undefined> {\n try {\n return ctx === undefined ? await cf.cfAppsDirect() : await cf.cfApps(ctx);\n } catch {\n return;\n }\n}\n\nasync function buildCandidates(\n config: TunnelFallbackConfig,\n ctx: CfExecContext | undefined,\n hintApp: string | undefined,\n): Promise<readonly string[]> {\n const stdout = await discoverAppsStdout(ctx);\n const base = buildCandidateList(config.appName, stdout, DEFAULT_TUNNEL_MAX_CANDIDATES);\n return hintApp === undefined || base.includes(hintApp) ? base : [hintApp, ...base];\n}\n\nasync function finalizeCandidateConnection(\n app: string,\n spawned: SpawnTunnelResult,\n driver: HanaDriver,\n config: TunnelFallbackConfig,\n directParams: DriverConnectParams,\n cacheOptions: TunnelCacheOptions,\n): Promise<DriverConnection | undefined> {\n const readyRecord = {\n localPort: spawned.localPort,\n pid: spawned.pid,\n app,\n orgKey: orgKeyOf(config),\n expiresAt: tunnelExpiryIso(),\n };\n try {\n const connection = await driver.connect(tunneledParams(directParams, spawned.localPort));\n await discardQuietly(finalizeEstablishingReady(config.host, readyRecord, cacheOptions));\n config.onTunnelStatus?.(`connected via SSH tunnel through ${app}`);\n return connection;\n } catch (error) {\n if (isConnectivityFailure(error)) {\n await discardQuietly(finalizeEstablishingFailed(config.host, cacheOptions));\n killTunnelProcess(spawned.pid);\n return undefined;\n }\n // The network path is proven even though this specific statement/setup\n // failed for an unrelated reason - keep the tunnel, surface the error.\n await discardQuietly(finalizeEstablishingReady(config.host, readyRecord, cacheOptions));\n throw error;\n }\n}\n\nasync function tryCandidate(\n app: string,\n ctx: CfExecContext | undefined,\n driver: HanaDriver,\n config: TunnelFallbackConfig,\n directParams: DriverConnectParams,\n deadline: number,\n overrides: TunnelFallbackOverrides,\n): Promise<DriverConnection | undefined> {\n const cacheOptions = overrides.cache ?? {};\n config.onTunnelStatus?.(`trying to reach ${config.host} via app ${app}...`);\n const claim = await claimEstablishing(config.host, process.pid, orgKeyOf(config), cacheOptions);\n\n if (claim.outcome === \"already-ready\") {\n return await tryReadyRecord(claim.record, driver, config, directParams, cacheOptions);\n }\n if (claim.outcome === \"wait\") {\n const ready = await waitForEstablishment(config.host, deadline, undefined, cacheOptions);\n return ready === undefined\n ? undefined\n : await tryReadyRecord(ready, driver, config, directParams, cacheOptions);\n }\n\n // Not caught here: a config error (e.g. an invalid keepalive value) is\n // static across every candidate, so it should abort the whole attempt\n // instead of being silently retried candidate-by-candidate.\n const spawned = await spawnTunnel(\n {\n cfHome: ctx?.cfHome,\n app,\n hanaHost: config.host,\n hanaPort: config.port,\n keepaliveSeconds: DEFAULT_TUNNEL_KEEPALIVE_SECONDS,\n deadline,\n candidateTimeoutMs: DEFAULT_TUNNEL_CANDIDATE_TIMEOUT_MS,\n },\n overrides.process ?? {},\n );\n\n if (spawned === undefined) {\n await discardQuietly(finalizeEstablishingFailed(config.host, cacheOptions));\n return undefined;\n }\n return await finalizeCandidateConnection(app, spawned, driver, config, directParams, cacheOptions);\n}\n\nasync function tryCachedTunnel(\n driver: HanaDriver,\n config: TunnelFallbackConfig,\n directParams: DriverConnectParams,\n cacheOptions: TunnelCacheOptions,\n): Promise<{ readonly connection: DriverConnection | undefined; readonly hintApp: string | undefined }> {\n if (config.refreshTunnel) {\n // Not just \"skip reuse\": an un-evicted stale record would still be\n // sitting there as a \"ready\" entry, and claimEstablishing's own\n // already-ready detection (meant for a *different* invocation finishing\n // concurrently) would hand it right back out during discovery below.\n await discardQuietly(evictTunnelCache(config.host, cacheOptions));\n return { connection: undefined, hintApp: undefined };\n }\n const entry = await readTunnelCacheEntry(config.host, cacheOptions);\n if (entry?.status !== \"ready\") {\n return { connection: undefined, hintApp: undefined };\n }\n if (!(await isTunnelUsable(entry, cacheOptions))) {\n await discardQuietly(evictTunnelCache(config.host, cacheOptions));\n return { connection: undefined, hintApp: entry.app };\n }\n const connection = await tryReadyRecord(entry, driver, config, directParams, cacheOptions);\n return { connection, hintApp: entry.app };\n}\n\nasync function tryDirectConnect(\n driver: HanaDriver,\n config: TunnelFallbackConfig,\n directParams: DriverConnectParams,\n): Promise<{ readonly connection: DriverConnection | undefined; readonly directError: unknown }> {\n if (config.tunnelMode !== \"auto\") {\n return { connection: undefined, directError: undefined };\n }\n try {\n return { connection: await driver.connect(directParams), directError: undefined };\n } catch (error) {\n if (!isConnectivityFailure(error)) {\n throw error;\n }\n return { connection: undefined, directError: error };\n }\n}\n\nfunction buildExhaustionError(host: string, directError: unknown, candidates: readonly string[]): unknown {\n if (directError !== undefined) {\n return directError;\n }\n return new CfHanaError(\n \"CONNECTION\",\n `Could not establish an SSH tunnel to ${host} through any candidate app ` +\n `(tried: ${candidates.length > 0 ? candidates.join(\", \") : \"none\"})`,\n );\n}\n\ninterface CandidateLoopResult {\n readonly connection: DriverConnection | undefined;\n readonly candidatesTried: readonly string[];\n}\n\nasync function runCandidateLoop(\n ctx: CfExecContext | undefined,\n driver: HanaDriver,\n config: TunnelFallbackConfig,\n directParams: DriverConnectParams,\n deadline: number,\n hintApp: string | undefined,\n overrides: TunnelFallbackOverrides,\n): Promise<CandidateLoopResult> {\n const candidatesTried = await buildCandidates(config, ctx, hintApp);\n for (const app of candidatesTried) {\n if (Date.now() >= deadline) {\n break;\n }\n const connection = await tryCandidate(app, ctx, driver, config, directParams, deadline, overrides);\n if (connection !== undefined) {\n return { connection, candidatesTried };\n }\n }\n return { connection: undefined, candidatesTried };\n}\n\n/**\n * The tunnel-fallback orchestration `Connection.open` calls instead of\n * `driver.connect()` directly. See `implementation_plan.md` for the full\n * design rationale (classifier reuse points, cache-first check in both\n * modes, self-healing reuse, shared deadline, mode-dependent exhaustion).\n */\nexport async function connectWithTunnelFallback(\n driver: HanaDriver,\n config: TunnelFallbackConfig,\n overrides: TunnelFallbackOverrides = {},\n): Promise<DriverConnection> {\n const directParams = directParamsOf(config);\n const cacheOptions = overrides.cache ?? {};\n\n await discardQuietly(reapStaleAndCrossOrgTunnels(orgKeyOf(config), cacheOptions));\n\n const cached = await tryCachedTunnel(driver, config, directParams, cacheOptions);\n if (cached.connection !== undefined) {\n return cached.connection;\n }\n\n const direct = await tryDirectConnect(driver, config, directParams);\n if (direct.connection !== undefined) {\n return direct.connection;\n }\n\n const deadline = Date.now() + DEFAULT_TUNNEL_FALLBACK_BUDGET_MS;\n const target = {\n apiEndpoint: config.apiEndpoint,\n orgName: config.orgName,\n spaceName: config.spaceName,\n };\n const loopResult = await withScopedCfSession(\n config.selectorSource,\n target,\n config.sapCredentials,\n (ctx) => runCandidateLoop(ctx, driver, config, directParams, deadline, cached.hintApp, overrides),\n );\n\n if (loopResult.connection !== undefined) {\n return loopResult.connection;\n }\n throw buildExhaustionError(config.host, direct.directError, loopResult.candidatesTried);\n}\n","import type { SapCredentials } from \"./config.js\";\nimport type { DriverConnection, HanaDriver } from \"./driver/types.js\";\nimport { CfHanaError, DestructiveStatementError, ReadOnlyViolationError } from \"./errors.js\";\nimport { applyAutoLimit, evaluateGuard } from \"./safety.js\";\nimport { assertParamArity, classifyStatement } from \"./statements.js\";\nimport { connectWithTunnelFallback } from \"./tunnel/fallback.js\";\nimport type {\n QueryOptions,\n QueryResult,\n QueryResultColumn,\n QueryRow,\n SelectorSource,\n SqlParam,\n} from \"./types.js\";\n\nexport interface ConnectionConfig {\n readonly host: string;\n readonly port: number;\n readonly user: string;\n readonly password: string;\n readonly schema: string;\n readonly certificate: string;\n readonly connectTimeoutMs: number;\n readonly queryTimeoutMs: number;\n readonly readOnly: boolean;\n readonly allowDestructive: boolean;\n readonly autoLimit: number | false;\n /** The resolved Cloud Foundry app/org/space/API this connection targets. */\n readonly appName: string;\n readonly orgName: string;\n readonly spaceName: string;\n readonly apiEndpoint: string;\n readonly selectorSource: SelectorSource;\n /** SAP BTP identity used to resolve bindings, reused for tunnel-fallback CF sessions. */\n readonly sapCredentials?: SapCredentials;\n /** `\"always\"` skips the direct attempt and connects via a tunnel immediately. */\n readonly tunnelMode: \"auto\" | \"always\";\n /** Bypasses a cached/live tunnel and forces a fresh establishment attempt. */\n readonly refreshTunnel: boolean;\n /** CLI-only stderr visibility hook; left unset, the library stays silent. */\n readonly onTunnelStatus?: (message: string) => void;\n}\n\ninterface RunOptions {\n readonly bypassSafety?: boolean;\n}\n\nfunction assertValidAutoLimit(value: number | false): void {\n if (\n value !== false &&\n (!Number.isSafeInteger(value) || value <= 0 || value >= Number.MAX_SAFE_INTEGER)\n ) {\n throw new CfHanaError(\"CONFIG\", \"autoLimit must be a positive safe integer\");\n }\n}\n\nfunction boundedRows(\n rows: readonly Record<string, SqlParam>[],\n requestedLimit: number | undefined,\n): {\n readonly rows: readonly Record<string, SqlParam>[];\n readonly truncated: boolean;\n} {\n if (requestedLimit === undefined) {\n return { rows, truncated: false };\n }\n return {\n rows: rows.slice(0, requestedLimit),\n truncated: rows.length > requestedLimit,\n };\n}\n\nfunction isBooleanColumn(column: QueryResultColumn): boolean {\n return column.typeName.trim().toUpperCase() === \"BOOLEAN\";\n}\n\nfunction normalizeBooleanCell(value: SqlParam): SqlParam {\n if (value === 0) {\n return false;\n }\n if (value === 1) {\n return true;\n }\n if (typeof value !== \"string\") {\n return value;\n }\n\n const normalized = value.trim().toLowerCase();\n if (normalized === \"0\") {\n return false;\n }\n if (normalized === \"1\") {\n return true;\n }\n if (normalized === \"false\") {\n return false;\n }\n if (normalized === \"true\") {\n return true;\n }\n return value;\n}\n\nfunction normalizeBooleanRow(\n row: Record<string, SqlParam>,\n columns: readonly QueryResultColumn[],\n): Record<string, SqlParam> {\n let normalizedRow: Record<string, SqlParam> | undefined;\n for (const column of columns) {\n const value = row[column.name];\n if (value === undefined) {\n continue;\n }\n const normalizedValue = normalizeBooleanCell(value);\n if (normalizedValue === value) {\n continue;\n }\n normalizedRow ??= { ...row };\n normalizedRow[column.name] = normalizedValue;\n }\n return normalizedRow ?? row;\n}\n\nfunction normalizeBooleanRows(\n rows: readonly Record<string, SqlParam>[],\n columns: readonly QueryResultColumn[],\n): readonly Record<string, SqlParam>[] {\n const booleanColumns = columns.filter(isBooleanColumn);\n if (booleanColumns.length === 0 || rows.length === 0) {\n return rows;\n }\n return rows.map((row) => normalizeBooleanRow(row, booleanColumns));\n}\n\nasync function withTimeout<T>(\n work: Promise<T>,\n timeoutMs: number,\n onTimeout: () => void,\n): Promise<T> {\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n onTimeout();\n reject(\n new CfHanaError(\"TIMEOUT\", `Statement timed out after ${String(timeoutMs)}ms`),\n );\n }, timeoutMs);\n timer.unref();\n });\n\n try {\n return await Promise.race([work, timeout]);\n } finally {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n }\n}\n\n/** A single HANA connection: applies the safety guard, auto-limit, and timeouts. */\nexport class Connection {\n private constructor(\n private readonly driverConnection: DriverConnection,\n private readonly config: ConnectionConfig,\n ) {}\n\n static async open(driver: HanaDriver, config: ConnectionConfig): Promise<Connection> {\n const driverConnection = await connectWithTunnelFallback(driver, config);\n return new Connection(driverConnection, config);\n }\n\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n const result = await this.run(sql, params ?? [], options ?? {});\n // The driver returns untyped rows; the caller asserts the row shape via TRow.\n return result as unknown as QueryResult<TRow>;\n }\n\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.run(sql, params ?? [], options ?? {});\n }\n\n assertAllowed(sql: string, options?: QueryOptions): void {\n this.evaluateSafety(sql, options ?? {});\n }\n\n async executeInternal(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.run(sql, params ?? [], options ?? {}, { bypassSafety: true });\n }\n\n async setAutoCommit(enabled: boolean): Promise<void> {\n await this.driverConnection.setAutoCommit(enabled);\n }\n\n async commit(): Promise<void> {\n await this.driverConnection.commit();\n }\n\n async rollback(): Promise<void> {\n await this.driverConnection.rollback();\n }\n\n async close(): Promise<void> {\n await this.driverConnection.close();\n }\n\n get isClosed(): boolean {\n return this.driverConnection.isClosed();\n }\n\n private async run(\n sql: string,\n params: readonly SqlParam[],\n options: QueryOptions,\n runOptions: RunOptions = {},\n ): Promise<QueryResult> {\n assertParamArity(sql, params);\n if (runOptions.bypassSafety !== true) {\n this.evaluateSafety(sql, options);\n }\n\n const kind = classifyStatement(sql);\n const autoLimit = options.autoLimit ?? this.config.autoLimit;\n assertValidAutoLimit(autoLimit);\n const limited =\n kind === \"select\" ? applyAutoLimit(sql, autoLimit) : { sql, applied: false };\n const timeoutMs = options.timeoutMs ?? this.config.queryTimeoutMs;\n\n const started = Date.now();\n const execResult = await withTimeout(\n this.driverConnection.exec(limited.sql, params),\n timeoutMs,\n () => {\n void this.closeQuietly();\n },\n );\n const elapsedMs = Date.now() - started;\n const normalizedRows = normalizeBooleanRows(execResult.rows, execResult.columns);\n const selected = boundedRows(normalizedRows, limited.requestedLimit);\n\n return {\n rows: selected.rows,\n columns: execResult.columns,\n rowCount: kind === \"select\" ? selected.rows.length : execResult.affectedRows,\n statement: kind,\n truncated: selected.truncated,\n elapsedMs,\n };\n }\n\n private async closeQuietly(): Promise<void> {\n try {\n await this.driverConnection.close();\n } catch {\n // Best-effort close after a timeout; the connection is already unusable.\n }\n }\n\n private evaluateSafety(sql: string, options: QueryOptions): void {\n const decision = evaluateGuard(sql, {\n readOnly: this.config.readOnly,\n allowDestructive: options.allowDestructive ?? this.config.allowDestructive,\n });\n if (decision.allowed) {\n return;\n }\n if (decision.violation === \"read-only\") {\n throw new ReadOnlyViolationError(\n decision.reason ?? \"read-only mode blocks this statement\",\n );\n }\n throw new DestructiveStatementError(\n decision.reason ?? \"destructive statement blocked\",\n );\n }\n}\n","import { DEFAULT_POOL_IDLE_MS, DEFAULT_POOL_MAX } from \"./config.js\";\nimport { Connection } from \"./connection.js\";\nimport type { ConnectionConfig } from \"./connection.js\";\nimport type { HanaDriver } from \"./driver/types.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport type { PoolOptions } from \"./types.js\";\n\ninterface IdleEntry {\n readonly connection: Connection;\n readonly since: number;\n}\n\ninterface Waiter {\n readonly resolve: (connection: Connection) => void;\n readonly reject: (error: unknown) => void;\n}\n\nasync function closeQuietly(connection: Connection): Promise<void> {\n try {\n await connection.close();\n } catch {\n // Best-effort close.\n }\n}\n\n/**\n * A process-local, in-memory pool of HANA connections. It holds no shared disk\n * state, so multiple pools (in this or other processes) are fully independent.\n */\nexport class ConnectionPool {\n private readonly idle: IdleEntry[] = [];\n private readonly busy = new Set<Connection>();\n private readonly waiters: Waiter[] = [];\n private readonly maxSize: number;\n private readonly idleTimeoutMs: number;\n private created = 0;\n private draining = false;\n\n constructor(\n private readonly driver: HanaDriver,\n private readonly config: ConnectionConfig,\n options?: PoolOptions,\n ) {\n this.maxSize = Math.max(1, options?.max ?? DEFAULT_POOL_MAX);\n this.idleTimeoutMs = options?.idleTimeoutMs ?? DEFAULT_POOL_IDLE_MS;\n }\n\n /** Total connections currently owned by the pool (idle + busy). */\n get size(): number {\n return this.created;\n }\n\n /** Connections currently idle and immediately reusable. */\n get available(): number {\n return this.idle.length;\n }\n\n /** Borrow a connection, opening or queueing as needed. */\n async acquire(): Promise<Connection> {\n if (this.draining) {\n throw new CfHanaError(\"POOL_CLOSED\", \"Connection pool is draining\");\n }\n\n const reused = this.takeIdleConnection();\n if (reused !== undefined) {\n this.busy.add(reused);\n return reused;\n }\n\n if (this.created < this.maxSize) {\n return await this.openBusyConnection();\n }\n\n return await new Promise<Connection>((resolve, reject) => {\n this.waiters.push({ resolve, reject });\n });\n }\n\n /** Return a borrowed connection to the pool. */\n release(connection: Connection): void {\n if (!this.busy.delete(connection)) {\n return;\n }\n\n if (connection.isClosed) {\n this.created -= 1;\n this.servePendingWaiters();\n return;\n }\n\n const waiter = this.waiters.shift();\n if (waiter !== undefined) {\n this.busy.add(connection);\n waiter.resolve(connection);\n return;\n }\n\n if (this.draining) {\n this.created -= 1;\n void closeQuietly(connection);\n return;\n }\n\n this.idle.push({ connection, since: Date.now() });\n }\n\n /** Run `work` with a borrowed connection, releasing it afterwards. */\n async withConnection<T>(work: (connection: Connection) => Promise<T>): Promise<T> {\n const connection = await this.acquire();\n try {\n return await work(connection);\n } finally {\n this.release(connection);\n }\n }\n\n /** Reject queued waiters and close idle connections. */\n async drain(): Promise<void> {\n this.draining = true;\n\n while (this.waiters.length > 0) {\n const waiter = this.waiters.shift();\n if (waiter !== undefined) {\n waiter.reject(new CfHanaError(\"POOL_CLOSED\", \"Connection pool was drained\"));\n }\n }\n\n const idleConnections = this.idle.splice(0).map((entry) => entry.connection);\n this.created -= idleConnections.length;\n await Promise.all(idleConnections.map((connection) => closeQuietly(connection)));\n }\n\n private takeIdleConnection(): Connection | undefined {\n for (;;) {\n const entry = this.idle.pop();\n if (entry === undefined) {\n return undefined;\n }\n if (entry.connection.isClosed) {\n this.created -= 1;\n continue;\n }\n if (this.idleTimeoutMs > 0 && Date.now() - entry.since > this.idleTimeoutMs) {\n this.created -= 1;\n void closeQuietly(entry.connection);\n continue;\n }\n return entry.connection;\n }\n }\n\n private async openBusyConnection(): Promise<Connection> {\n this.created += 1;\n let connection: Connection;\n try {\n connection = await Connection.open(this.driver, this.config);\n } catch (error) {\n this.created -= 1;\n throw error;\n }\n this.busy.add(connection);\n return connection;\n }\n\n private servePendingWaiters(): void {\n while (this.waiters.length > 0 && this.created < this.maxSize) {\n const waiter = this.waiters.shift();\n if (waiter === undefined) {\n return;\n }\n this.created += 1;\n void Connection.open(this.driver, this.config).then(\n (connection) => {\n this.busy.add(connection);\n waiter.resolve(connection);\n },\n (error: unknown) => {\n this.created -= 1;\n waiter.reject(error);\n this.servePendingWaiters();\n },\n );\n }\n }\n}\n","import type { Connection } from \"./connection.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport type { QueryOptions, QueryResult, QueryRow, SqlParam } from \"./types.js\";\n\n/** A HANA transaction bound to one connection with autocommit disabled. */\nexport class Transaction {\n private finished = false;\n\n constructor(private readonly connection: Connection) {}\n\n /** Whether the transaction has already been committed or rolled back. */\n get isFinished(): boolean {\n return this.finished;\n }\n\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n this.assertActive();\n return await this.connection.query<TRow>(sql, params, options);\n }\n\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n this.assertActive();\n return await this.connection.execute(sql, params, options);\n }\n\n async commit(): Promise<void> {\n this.assertActive();\n this.finished = true;\n await this.connection.commit();\n }\n\n async rollback(): Promise<void> {\n this.assertActive();\n this.finished = true;\n await this.connection.rollback();\n }\n\n private assertActive(): void {\n if (this.finished) {\n throw new CfHanaError(\n \"QUERY\",\n \"This transaction has already been committed or rolled back\",\n );\n }\n }\n}\n","import { buildWriteBackupPlan, writeSqlBackup } from \"./backup.js\";\nimport type { SqlBackupRecord } from \"./backup.js\";\nimport { buildCount, buildDelete, buildInsert, buildSelect, buildUpdate } from \"./builder.js\";\nimport { listCatalogObjects, listColumns, listSchemas, listTables } from \"./catalog.js\";\nimport {\n DEFAULT_AUTO_LIMIT,\n CLI_VERSION,\n DEFAULT_CONNECT_TIMEOUT_MS,\n DEFAULT_QUERY_TIMEOUT_MS,\n readSapCredentials,\n} from \"./config.js\";\nimport type { ConnectionConfig } from \"./connection.js\";\nimport { resolveAppBindings, selectBinding, toConnectionTarget } from \"./credentials.js\";\nimport type { ResolvedBindings, SelectedConnectionTarget } from \"./credentials.js\";\nimport { createDriver } from \"./driver/index.js\";\nimport { appendSqlHistory } from \"./history.js\";\nimport type { SqlHistoryOperation } from \"./history.js\";\nimport type { CatalogObjectInfo } from \"./metadata-cache.js\";\nimport { ConnectionPool } from \"./pool.js\";\nimport { Transaction } from \"./transaction.js\";\nimport type {\n ColumnInfo,\n ConnectOptions,\n DbUserRole,\n HanaBinding,\n HanaClientInfo,\n PoolOptions,\n QueryOptions,\n QueryResult,\n QueryRow,\n SelectSpec,\n SqlParam,\n TableInfo,\n} from \"./types.js\";\n\nlet explainStatementCounter = 0;\n\ninterface SelectedBindingInfo {\n readonly bindingName?: string;\n readonly bindingIndex: number;\n readonly availableBindingNames: readonly string[];\n}\n\nfunction nextExplainStatementName(): string {\n explainStatementCounter = (explainStatementCounter + 1) % Number.MAX_SAFE_INTEGER;\n return `cf_hana_${String(process.pid)}_${String(Date.now())}_${String(explainStatementCounter)}`;\n}\n\nfunction toPoolOptions(options: ConnectOptions): PoolOptions {\n if (options.pool === false) {\n return { max: 1 };\n }\n return options.pool ?? {};\n}\n\n/** Build the frozen per-client connection config, including tunnel-fallback context. */\nexport function buildConnectionConfig(\n resolved: ResolvedBindings,\n target: SelectedConnectionTarget,\n options: ConnectOptions,\n): ConnectionConfig {\n const sapCredentials = readSapCredentials({ email: options.email, password: options.password });\n return {\n host: target.host,\n port: target.port,\n user: target.user,\n password: target.password,\n schema: target.schema,\n certificate: target.certificate,\n connectTimeoutMs: options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,\n queryTimeoutMs: options.queryTimeoutMs ?? DEFAULT_QUERY_TIMEOUT_MS,\n readOnly: options.readOnly ?? false,\n allowDestructive: options.allowDestructive ?? false,\n autoLimit: options.autoLimit ?? DEFAULT_AUTO_LIMIT,\n appName: resolved.appName,\n orgName: resolved.orgName,\n spaceName: resolved.spaceName,\n apiEndpoint: resolved.apiEndpoint,\n selectorSource: resolved.selectorSource,\n tunnelMode: options.tunnel === true ? \"always\" : \"auto\",\n refreshTunnel: options.refreshTunnel ?? false,\n ...(sapCredentials === undefined ? {} : { sapCredentials }),\n ...(options.onTunnelStatus === undefined ? {} : { onTunnelStatus: options.onTunnelStatus }),\n };\n}\n\nfunction toSelectedBindingInfo(\n bindings: readonly HanaBinding[],\n selected: HanaBinding,\n): SelectedBindingInfo {\n const availableBindingNames = bindings.flatMap((binding) =>\n binding.name === undefined ? [] : [binding.name],\n );\n return {\n ...(selected.name === undefined ? {} : { bindingName: selected.name }),\n bindingIndex: bindings.indexOf(selected),\n availableBindingNames,\n };\n}\n\n/**\n * The high-level entry point: a pooled, reusable client for the HANA database\n * bound to a single Cloud Foundry app.\n */\nexport class HanaClient {\n constructor(\n private readonly pool: ConnectionPool,\n readonly info: HanaClientInfo,\n readonly databaseUser = \"\",\n ) {}\n\n /** Open a client for a `region/org/space/app` selector (or a bare app name). */\n static async connect(selector: string, options: ConnectOptions = {}): Promise<HanaClient> {\n const resolved = await resolveAppBindings(selector, options);\n const role: DbUserRole = options.role ?? \"runtime\";\n const binding = selectBinding(resolved.bindings, options);\n const bindingInfo = toSelectedBindingInfo(resolved.bindings, binding);\n const target = toConnectionTarget(binding, role);\n const driver = createDriver();\n const config = buildConnectionConfig(resolved, target, options);\n const poolOptions = toPoolOptions(options);\n\n const info: HanaClientInfo = {\n selector: resolved.selector,\n appName: resolved.appName,\n host: target.host,\n schema: target.schema,\n role,\n driver: driver.name,\n credentialSource: resolved.source,\n selectorSource: resolved.selectorSource,\n regionConfirmed: resolved.regionConfirmed,\n selectorCanBePinned: resolved.selectorCanBePinned,\n ...bindingInfo,\n };\n return new HanaClient(new ConnectionPool(driver, config, poolOptions), info, target.user);\n }\n\n /** Run a SELECT (or any read) statement and return typed rows. */\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n const resolvedParams = params ?? [];\n const result = await this.runQuery<TRow>(sql, resolvedParams, options);\n await this.recordSqlHistory(\"query\", sql, resolvedParams, result);\n return result;\n }\n\n /** Run a DML/DDL statement and return its affected-row count. */\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n const resolvedParams = params ?? [];\n const result = await this.runExecute(sql, resolvedParams, options);\n await this.recordSqlHistory(\"execute\", sql, resolvedParams, result);\n return result;\n }\n\n /** Back up pre-image rows required by a supported write before the caller runs it. */\n async backupWriteStatement(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<SqlBackupRecord | undefined> {\n const resolvedParams = params ?? [];\n const plan = buildWriteBackupPlan(sql, resolvedParams);\n if (plan === undefined) {\n return undefined;\n }\n\n return await this.pool.withConnection(async (connection) => {\n connection.assertAllowed(plan.statementSql, options);\n const backupQueryOptions: QueryOptions = {\n autoLimit: false,\n ...(options?.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),\n };\n const result = await connection.query(plan.selectSql, plan.selectParams, backupQueryOptions);\n return await writeSqlBackup({\n operation: plan.operation,\n statementSql: plan.statementSql,\n result,\n selector: this.info.selector,\n });\n });\n }\n\n /** Run a typed `SELECT` built from a spec. */\n async selectFrom<TRow = QueryRow>(spec: SelectSpec): Promise<QueryResult<TRow>> {\n const built = buildSelect(spec);\n return await this.runQuery<TRow>(built.sql, built.params);\n }\n\n /** Count rows in a table, optionally filtered. */\n async count(spec: Pick<SelectSpec, \"schema\" | \"table\" | \"where\">): Promise<number> {\n const built = buildCount(spec);\n const result = await this.runQuery<{ COUNT: number }>(built.sql, built.params);\n return result.rows[0]?.COUNT ?? 0;\n }\n\n /** Insert a single row. */\n async insertInto(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildInsert(schema, table, values);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Update rows matching a non-empty `where` filter. */\n async update(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n where: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildUpdate(schema, table, values, where);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Delete rows matching a non-empty `where` filter. */\n async deleteFrom(\n schema: string,\n table: string,\n where: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildDelete(schema, table, where);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Run `work` inside a transaction, auto-committing on success. */\n async transaction<T>(work: (tx: Transaction) => Promise<T>): Promise<T> {\n return await this.pool.withConnection(async (connection) => {\n await connection.setAutoCommit(false);\n const tx = new Transaction(connection);\n try {\n const result = await work(tx);\n if (!tx.isFinished) {\n await tx.commit();\n }\n return result;\n } catch (error) {\n if (!tx.isFinished) {\n try {\n await tx.rollback();\n } catch {\n // Preserve the original error; ignore a rollback failure.\n }\n }\n throw error;\n } finally {\n await connection.setAutoCommit(true);\n }\n });\n }\n\n /** List every schema visible to the connected user. */\n async listSchemas(): Promise<readonly string[]> {\n return await this.pool.withConnection((connection) => listSchemas(connection));\n }\n\n /** List the tables in a schema. */\n async listTables(schema: string): Promise<readonly TableInfo[]> {\n return await this.pool.withConnection((connection) => listTables(connection, schema));\n }\n\n /** List table and view names in a schema for typo suggestions. */\n async listCatalogObjects(schema: string): Promise<readonly CatalogObjectInfo[]> {\n return await this.pool.withConnection((connection) => listCatalogObjects(connection, schema));\n }\n\n /** List the columns of a table. */\n async listColumns(schema: string, table: string): Promise<readonly ColumnInfo[]> {\n return await this.pool.withConnection((connection) =>\n listColumns(connection, schema, table),\n );\n }\n\n /** Return the HANA execution plan for a statement. */\n async explain(sql: string, params?: readonly SqlParam[]): Promise<QueryResult> {\n return await this.pool.withConnection(async (connection) => {\n connection.assertAllowed(sql);\n const statementName = nextExplainStatementName();\n await connection.executeInternal(\n `EXPLAIN PLAN SET STATEMENT_NAME = '${statementName}' FOR ${sql}`,\n params,\n );\n const cleanup = async (): Promise<void> => {\n await connection.executeInternal(\n \"DELETE FROM EXPLAIN_PLAN_TABLE WHERE STATEMENT_NAME = ?\",\n [statementName],\n );\n };\n let queryCompleted = false;\n try {\n const result = await connection.query(\n \"SELECT OPERATOR_NAME, TABLE_NAME, TABLE_TYPE, EXECUTION_ENGINE \" +\n \"FROM EXPLAIN_PLAN_TABLE WHERE STATEMENT_NAME = ? ORDER BY OPERATOR_ID\",\n [statementName],\n );\n queryCompleted = true;\n await cleanup();\n return result;\n } catch (error) {\n if (!queryCompleted) {\n try {\n await cleanup();\n } catch {\n // Preserve the original explain-plan read error.\n }\n }\n throw error;\n }\n });\n }\n\n /** Close every pooled connection. The client must not be used afterwards. */\n async close(): Promise<void> {\n await this.pool.drain();\n }\n\n private async runQuery<TRow = QueryRow>(\n sql: string,\n params: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n return await this.pool.withConnection((connection) =>\n connection.query<TRow>(sql, params, options),\n );\n }\n\n private async runExecute(\n sql: string,\n params: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.pool.withConnection((connection) =>\n connection.execute(sql, params, options),\n );\n }\n\n private async recordSqlHistory<TRow>(\n operation: SqlHistoryOperation,\n sql: string,\n params: readonly SqlParam[],\n result: QueryResult<TRow>,\n ): Promise<void> {\n try {\n await appendSqlHistory({\n version: CLI_VERSION,\n operation,\n selector: this.info.selector,\n appName: this.info.appName,\n schema: this.info.schema,\n role: this.info.role,\n statement: result.statement,\n sql,\n paramCount: params.length,\n rowCount: result.rowCount,\n truncated: result.truncated,\n elapsedMs: result.elapsedMs,\n });\n } catch {\n // History is diagnostic local state; never fail a successful SQL statement.\n }\n }\n}\n","import { HanaClient } from \"./client.js\";\nimport type {\n ConnectOptions,\n QueryOptions,\n QueryResult,\n QueryRow,\n SqlParam,\n} from \"./types.js\";\n\n/**\n * Open a reusable, pooled client for the HANA database bound to a Cloud Foundry\n * app, addressed by a `region/org/space/app` selector or a bare app name.\n */\nexport async function connect(\n selector: string,\n options?: ConnectOptions,\n): Promise<HanaClient> {\n return await HanaClient.connect(selector, options);\n}\n\n/**\n * Connect, run a single query, and close — the one-shot convenience for scripts.\n */\nexport async function query<TRow = QueryRow>(\n selector: string,\n sql: string,\n params?: readonly SqlParam[],\n options?: ConnectOptions & QueryOptions,\n): Promise<QueryResult<TRow>> {\n const client = await HanaClient.connect(selector, options);\n try {\n return await client.query<TRow>(sql, params, options);\n } finally {\n await client.close();\n }\n}\n\n/** Run `work` with a client that is closed automatically afterwards. */\nexport async function withConnection<T>(\n selector: string,\n work: (client: HanaClient) => Promise<T>,\n options?: ConnectOptions,\n): Promise<T> {\n const client = await HanaClient.connect(selector, options);\n try {\n return await work(client);\n } finally {\n await client.close();\n }\n}\n"],"mappings":"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","names":["typeName","next","join","appendFile","mkdir","rm","homedir","join","SAPTOOLS_DIR_NAME","CF_HANA_DIR_NAME","defaultSaptoolsRoot","skipQuotedText","skipLineComment","skipBlockComment","mkdir","readdir","rm","writeFile","homedir","join","mkdtemp","rm","tmpdir","join","mkdtemp","join","tmpdir","rm","isRecord","join","homedir","mkdir","writeFile","rm","readdir"]}