@saptools/cf-hana 0.3.2 → 0.3.4

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/errors.ts","../src/lob.ts","../src/format.ts","../src/statements.ts","../src/builder.ts","../src/catalog.ts","../src/config.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 { QueryError } from \"./errors.js\";\nimport { formatCsv } from \"./format.js\";\nimport { assertParamArity, countPlaceholders, firstKeyword } from \"./statements.js\";\nimport type { QueryResult, SqlParam } from \"./types.js\";\n\nconst SAPTOOLS_DIR_NAME = \".saptools\";\nconst CF_HANA_DIR_NAME = \"cf-hana\";\nconst BACKUPS_DIR_NAME = \"backups\";\n\nexport type WriteBackupOperation = \"update\" | \"upsert\" | \"delete\";\n\nexport interface WriteBackupPlan {\n readonly operation: WriteBackupOperation;\n readonly statementSql: string;\n readonly selectSql: string;\n readonly selectParams: readonly SqlParam[];\n}\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}\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\ntype TopLevelKeyword = \"UPDATE\" | \"UPSERT\" | \"DELETE\" | \"SET\" | \"FROM\" | \"VALUES\" | \"WHERE\";\n\nfunction defaultSaptoolsRoot(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nfunction trimStatementSql(sql: string): string {\n return sql.trim().replace(/;+\\s*$/, \"\").trim();\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\nfunction keywordMatches(sql: string, index: number, keyword: TopLevelKeyword): 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\nfunction findTopLevelKeyword(\n sql: string,\n keyword: TopLevelKeyword,\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\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\nfunction 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\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\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): WriteBackupPlan {\n const upsertIndex = findTopLevelKeyword(statementSql, \"UPSERT\");\n const valuesIndex =\n upsertIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"VALUES\", upsertIndex + \"UPSERT\".length);\n if (upsertIndex === undefined || valuesIndex === undefined) {\n throw new QueryError(\"UPSERT backup requires UPSERT <target> VALUES syntax\");\n }\n\n const targetStart = upsertIndex + \"UPSERT\".length;\n const columnListIndex = findTopLevelChar(statementSql, \"(\", targetStart, valuesIndex);\n const targetEnd = columnListIndex ?? valuesIndex;\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", valuesIndex + \"VALUES\".length);\n return buildSelectPlan(\n \"upsert\",\n statementSql,\n statementSql.slice(targetStart, targetEnd),\n whereIndex,\n params,\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 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 function buildWriteBackupPlan(\n sql: string,\n params: readonly SqlParam[] = [],\n): WriteBackupPlan | undefined {\n const statementSql = trimStatementSql(sql);\n const keyword = firstKeyword(statementSql);\n if (keyword !== \"UPDATE\" && keyword !== \"UPSERT\" && keyword !== \"DELETE\") {\n return undefined;\n }\n\n assertParamArity(statementSql, params);\n if (keyword === \"UPDATE\") {\n return buildUpdateBackupPlan(statementSql, params);\n }\n if (keyword === \"UPSERT\") {\n return buildUpsertBackupPlan(statementSql, params);\n }\n return buildDeleteBackupPlan(statementSql, params);\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\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, formatCsv(input.result), { 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 type CfHanaErrorCode =\n | \"CONFIG\"\n | \"CREDENTIALS_NOT_FOUND\"\n | \"AMBIGUOUS_BINDING\"\n | \"CONNECTION\"\n | \"QUERY\"\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\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\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(result: QueryResult, format: OutputFormat): string {\n switch (format) {\n case \"table\":\n return formatTable(result);\n case \"json\":\n return formatJson(result);\n case \"csv\":\n return formatCsv(result);\n }\n}\n","import { QueryError } from \"./errors.js\";\nimport type { SqlParam, StatementKind } from \"./types.js\";\n\nconst LEADING_NOISE = /^(?:\\s|--[^\\n]*\\n?|\\/\\*[\\s\\S]*?\\*\\/)+/;\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 const stripped = sql.replace(LEADING_NOISE, \"\");\n const match = /^[A-Za-z]+/.exec(stripped);\n return (match?.[0] ?? \"\").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 { 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","export const CLI_NAME = \"cf-hana\";\nexport const CLI_VERSION = \"0.3.2\";\nexport const ENV_PREFIX = \"CF_HANA\";\n\nexport const DEFAULT_QUERY_TIMEOUT_MS = 30_000;\nexport const DEFAULT_CONNECT_TIMEOUT_MS = 30_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;\nexport const MAX_RESULT_STORE_BYTES = 256 * 1024 * 1024;\nexport const HANA_CLOUD_DEFAULT_PORT = 443;\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","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 = 30_000;\nconst CF_RETRY_ATTEMPTS = 3;\nconst CF_RETRY_BASE_DELAY_MS = 120;\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\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 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 eu10: \"https://api.cf.eu10.hana.ondemand.com\",\n eu11: \"https://api.cf.eu11.hana.ondemand.com\",\n eu12: \"https://api.cf.eu12.hana.ondemand.com\",\n eu20: \"https://api.cf.eu20.hana.ondemand.com\",\n eu21: \"https://api.cf.eu21.hana.ondemand.com\",\n eu30: \"https://api.cf.eu30.hana.ondemand.com\",\n \"eu10-002\": \"https://api.cf.eu10-002.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 us10: \"https://api.cf.us10.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 us30: \"https://api.cf.us30.hana.ondemand.com\",\n in30: \"https://api.cf.in30.hana.ondemand.com\",\n};\n\nexport function getApiEndpointForRegion(regionKey: string): string | undefined {\n return REGION_API_MAP[regionKey];\n}\n\nexport function getRegionKeyForApi(apiEndpoint: string): string | undefined {\n const norm = apiEndpoint.trim().replace(/\\/+$/, \"\").toLowerCase();\n for (const [key, endpoint] of Object.entries(REGION_API_MAP)) {\n if (endpoint.toLowerCase() === norm) {\n return key;\n }\n }\n return undefined;\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 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 let lastErr: unknown;\n\n for (let attempt = 0; attempt < CF_RETRY_ATTEMPTS; attempt++) {\n try {\n const { stdout } = await execFileAsync(bin, [...argsPrefix, ...args], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: DEFAULT_TIMEOUT_MS,\n });\n return stdout;\n } catch (err) {\n lastErr = err;\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\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\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 const { stdout } = await execFileAsync(bin, [...argsPrefix, \"env\", appName], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: DEFAULT_TIMEOUT_MS,\n });\n return stdout;\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 execFileAsync(bin, [...argsPrefix, \"target\"], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: 10_000,\n });\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 const regionKey = getRegionKeyForApi(api);\n return {\n apiEndpoint: api,\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 if (!target.regionKey) {\n throw new Error(\n `Current CF API endpoint \"${target.apiEndpoint}\" does not match a known SAP region. Pass a full region/org/space/app selector.`,\n );\n }\n return `${target.regionKey}/${target.orgName}/${target.spaceName}/${name}`;\n}\n\n/* VCAP parser */\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 extractHanaBindingsFromCfEnv,\n formatCurrentCfAppSelector,\n getApiEndpointForRegion,\n readCurrentCfTarget,\n withCfSession,\n} from \"./cf.js\";\nimport { readSapCredentials } from \"./config.js\";\nimport { CfHanaError, CredentialsNotFoundError } from \"./errors.js\";\nimport type { CredentialSource, DbUserRole, HanaBinding } from \"./types.js\";\n\nexport interface ResolveBindingsOptions {\n readonly refresh?: boolean;\n readonly email?: string;\n readonly password?: string;\n}\n\nexport interface ResolvedBindings {\n readonly selector: string;\n readonly appName: string;\n readonly bindings: readonly HanaBinding[];\n readonly source: CredentialSource;\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\n/**\n * Resolve an app's HANA bindings.\n *\n * Bare app name: resolve it against the current `cf target`.\n * - First try the user's *existing* CF session directly via cfEnvDirect (no re-auth).\n * - Only fall back to SAP + isolated re-auth if the error is classified as auth/session problem.\n * Explicit selector: Always full authenticated isolated path.\n *\n * This is the professional realization of the request:\n * When only an app is provided, the current CF target supplies org and space.\n * Auth/re-auth ONLY on session/unauthorize (per user feedback).\n */\nexport async function resolveAppBindings(\n rawSelector: string,\n options: ResolveBindingsOptions,\n): Promise<ResolvedBindings> {\n const selector = rawSelector.trim();\n if (!selector) {\n throw new CfHanaError(\"CONFIG\", \"App selector is required\");\n }\n\n let target: {\n selector: string;\n apiEndpoint?: string | undefined;\n orgName: string;\n spaceName: string;\n appName: string;\n };\n\n const isBare = !selector.includes(\"/\");\n\n if (isBare) {\n // A bare app inherits region, org, and space from the current CF target.\n const current = await readCurrentCfTarget();\n if (!current) {\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 const displaySelector = current.regionKey\n ? formatCurrentCfAppSelector(current, selector)\n : `current/${current.orgName}/${current.spaceName}/${selector}`;\n target = {\n selector: displaySelector,\n apiEndpoint: current.regionKey ? getApiEndpointForRegion(current.regionKey) : undefined,\n orgName: current.orgName,\n spaceName: current.spaceName,\n appName: selector,\n };\n } else {\n // Explicit: region/org/space/app\n const parts = selector.split(\"/\").map((p) => p.trim());\n if (parts.length !== 4 || !parts[0] || !parts[1] || !parts[2] || !parts[3]) {\n throw new CfHanaError(\n \"CONFIG\",\n `Invalid selector \"${selector}\". Use region/org/space/app or a bare app name.`,\n );\n }\n const [regionKey, orgName, spaceName, appName] = parts as [string, string, string, string];\n const apiEndpoint = getApiEndpointForRegion(regionKey);\n if (!apiEndpoint) {\n throw new CfHanaError(\n \"CONFIG\",\n `Unknown region key \"${regionKey}\". Use a known region or the current CF target.`,\n );\n }\n target = { selector, apiEndpoint, orgName, spaceName, appName };\n }\n\n let bindings: readonly HanaBinding[];\n const source: CredentialSource = \"live\";\n\n if (isBare) {\n // Preferred fast path for bare: use whatever CF context the user already has.\n // NO re-auth, NO new CF_HOME.\n try {\n const stdout = await cfEnvDirect(target.appName);\n bindings = extractHanaBindingsFromCfEnv(stdout);\n } catch (directError: unknown) {\n // Professional classification: only re-auth for real auth/session problems.\n let stderr = '';\n if (directError && typeof directError === 'object') {\n const e = directError as { stderr?: unknown; message?: unknown };\n stderr = (typeof e.stderr === 'string' ? e.stderr : '') || (typeof e.message === 'string' ? e.message : '');\n }\n const classified = classifyCfError(stderr);\n if (classified.isAuthError) {\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (!sap) {\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 if (!target.apiEndpoint) {\n throw new CfHanaError(\"CONFIG\", \"Cannot determine API endpoint for fallback auth.\");\n }\n const api = target.apiEndpoint;\n bindings = await withCfSession(async (ctx) => {\n await cfApi(api, ctx);\n await cfAuth(sap.email, sap.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n const stdout = await cfEnv(target.appName, ctx);\n return extractHanaBindingsFromCfEnv(stdout);\n });\n } else {\n // Not auth-related (e.g. app not present in current space)\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}\". ${stderr ? `Details: ${stderr}` : \"\"}`,\n { cause: directError }\n );\n }\n }\n } else {\n // Explicit selector always uses full authenticated isolated path\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (!sap) {\n throw new CredentialsNotFoundError(\n `SAP_EMAIL and SAP_PASSWORD are required to fetch HANA bindings for explicit selector \"${selector}\".`,\n );\n }\n if (!target.apiEndpoint) {\n throw new CfHanaError(\"CONFIG\", \"Invalid explicit selector.\");\n }\n const api = target.apiEndpoint;\n bindings = await withCfSession(async (ctx) => {\n await cfApi(api, ctx);\n await cfAuth(sap.email, sap.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n const stdout = await cfEnv(target.appName, ctx);\n return extractHanaBindingsFromCfEnv(stdout);\n });\n }\n\n if (bindings.length === 0) {\n throw new CredentialsNotFoundError(`App \"${target.selector}\" has no HANA service binding.`);\n }\n\n return {\n selector: target.selector,\n appName: target.appName,\n bindings,\n source,\n };\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 } 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 fakeExec(sql: string): DriverExecResult {\n const kind = classifyStatement(sql);\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 const upperSql = sql.toUpperCase();\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 {\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\n if (upperSql.includes(\"SYS.TABLE_COLUMNS\")) {\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\n if (upperSql.includes(\"MISSING_TABLE\") || upperSql.includes(\"MISSING_TABLES\")) {\n throw new QueryError(\"invalid table name: MISSING_TABLE\", { sqlState: \"42S02\" });\n }\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\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\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 if (sql.toUpperCase().includes(\"LOB_FIXTURE\")) {\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\n if (sql.toUpperCase().includes(\"DUMMY\")) {\n return {\n rows: [{ \"1\": 1 }],\n columns: [{ name: \"1\", typeName: \"INTEGER\" }],\n affectedRows: 0,\n };\n }\n\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\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 hasWhereClause(sql: string): boolean {\n return /\\bwhere\\b/i.test(maskIgnoredSqlText(sql));\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 return {\n kind,\n destructive: UNSCOPED_WRITE_KEYWORDS.has(keyword) && !hasWhereClause(sql),\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 or unscoped UPDATE/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 { QueryOptions, QueryResult, QueryRow, SqlParam } 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\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 selected = boundedRows(execResult.rows, 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 HanaClientInfo,\n PoolOptions,\n QueryOptions,\n QueryResult,\n QueryRow,\n SelectSpec,\n SqlParam,\n TableInfo,\n} from \"./types.js\";\n\nlet explainStatementCounter = 0;\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\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 ) {}\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 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: PoolOptions =\n options.pool === false ? { max: 1 } : (options.pool ?? {});\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 };\n return new HanaClient(new ConnectionPool(driver, config, poolOptions), info);\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 rows matched by an UPDATE or DELETE 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","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/errors.ts","../src/lob.ts","../src/format.ts","../src/statements.ts","../src/builder.ts","../src/catalog.ts","../src/config.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 { QueryError } from \"./errors.js\";\nimport { formatCsv } from \"./format.js\";\nimport { assertParamArity, countPlaceholders, firstKeyword } from \"./statements.js\";\nimport type { QueryResult, SqlParam } from \"./types.js\";\n\nconst SAPTOOLS_DIR_NAME = \".saptools\";\nconst CF_HANA_DIR_NAME = \"cf-hana\";\nconst BACKUPS_DIR_NAME = \"backups\";\n\nexport type WriteBackupOperation = \"update\" | \"upsert\" | \"delete\";\n\nexport interface WriteBackupPlan {\n readonly operation: WriteBackupOperation;\n readonly statementSql: string;\n readonly selectSql: string;\n readonly selectParams: readonly SqlParam[];\n}\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}\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\ntype TopLevelKeyword = \"UPDATE\" | \"UPSERT\" | \"DELETE\" | \"SET\" | \"FROM\" | \"VALUES\" | \"WHERE\";\n\nfunction defaultSaptoolsRoot(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nfunction trimStatementSql(sql: string): string {\n return sql.trim().replace(/;+\\s*$/, \"\").trim();\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\nfunction keywordMatches(sql: string, index: number, keyword: TopLevelKeyword): 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\nfunction findTopLevelKeyword(\n sql: string,\n keyword: TopLevelKeyword,\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\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\nfunction 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\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\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): WriteBackupPlan {\n const upsertIndex = findTopLevelKeyword(statementSql, \"UPSERT\");\n const valuesIndex =\n upsertIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"VALUES\", upsertIndex + \"UPSERT\".length);\n if (upsertIndex === undefined || valuesIndex === undefined) {\n throw new QueryError(\"UPSERT backup requires UPSERT <target> VALUES syntax\");\n }\n\n const targetStart = upsertIndex + \"UPSERT\".length;\n const columnListIndex = findTopLevelChar(statementSql, \"(\", targetStart, valuesIndex);\n const targetEnd = columnListIndex ?? valuesIndex;\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", valuesIndex + \"VALUES\".length);\n return buildSelectPlan(\n \"upsert\",\n statementSql,\n statementSql.slice(targetStart, targetEnd),\n whereIndex,\n params,\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 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 function buildWriteBackupPlan(\n sql: string,\n params: readonly SqlParam[] = [],\n): WriteBackupPlan | undefined {\n const statementSql = trimStatementSql(sql);\n const keyword = firstKeyword(statementSql);\n if (keyword !== \"UPDATE\" && keyword !== \"UPSERT\" && keyword !== \"DELETE\") {\n return undefined;\n }\n\n assertParamArity(statementSql, params);\n if (keyword === \"UPDATE\") {\n return buildUpdateBackupPlan(statementSql, params);\n }\n if (keyword === \"UPSERT\") {\n return buildUpsertBackupPlan(statementSql, params);\n }\n return buildDeleteBackupPlan(statementSql, params);\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\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, formatCsv(input.result), { 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 type CfHanaErrorCode =\n | \"CONFIG\"\n | \"CREDENTIALS_NOT_FOUND\"\n | \"AMBIGUOUS_BINDING\"\n | \"CONNECTION\"\n | \"QUERY\"\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\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\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(result: QueryResult, format: OutputFormat): string {\n switch (format) {\n case \"table\":\n return formatTable(result);\n case \"json\":\n return formatJson(result);\n case \"csv\":\n return formatCsv(result);\n }\n}\n","import { QueryError } from \"./errors.js\";\nimport type { SqlParam, StatementKind } from \"./types.js\";\n\nconst LEADING_NOISE = /^(?:\\s|--[^\\n]*\\n?|\\/\\*[\\s\\S]*?\\*\\/)+/;\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 const stripped = sql.replace(LEADING_NOISE, \"\");\n const match = /^[A-Za-z]+/.exec(stripped);\n return (match?.[0] ?? \"\").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 { 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","export const CLI_NAME = \"cf-hana\";\nexport const CLI_VERSION = \"0.3.4\";\nexport const ENV_PREFIX = \"CF_HANA\";\n\nexport const DEFAULT_QUERY_TIMEOUT_MS = 30_000;\nexport const DEFAULT_CONNECT_TIMEOUT_MS = 30_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;\nexport const MAX_RESULT_STORE_BYTES = 256 * 1024 * 1024;\nexport const HANA_CLOUD_DEFAULT_PORT = 443;\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","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 = 30_000;\nconst CF_RETRY_ATTEMPTS = 3;\nconst CF_RETRY_BASE_DELAY_MS = 120;\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\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 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 let lastErr: unknown;\n\n for (let attempt = 0; attempt < CF_RETRY_ATTEMPTS; attempt++) {\n try {\n const { stdout } = await execFileAsync(bin, [...argsPrefix, ...args], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: DEFAULT_TIMEOUT_MS,\n });\n return stdout;\n } catch (err) {\n lastErr = err;\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\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\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 const { stdout } = await execFileAsync(bin, [...argsPrefix, \"env\", appName], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: DEFAULT_TIMEOUT_MS,\n });\n return stdout;\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 execFileAsync(bin, [...argsPrefix, \"target\"], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: 10_000,\n });\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 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 extractHanaBindingsFromCfEnv,\n formatCurrentCfAppSelector,\n getApiEndpointForRegion,\n normalizeSapCfApiEndpoint,\n readCurrentCfTarget,\n withCfSession,\n} from \"./cf.js\";\nimport { readSapCredentials } from \"./config.js\";\nimport { CfHanaError, CredentialsNotFoundError } from \"./errors.js\";\nimport type { CredentialSource, DbUserRole, HanaBinding } 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}\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\n/**\n * Resolve an app's HANA bindings.\n *\n * Bare app name: resolve it against the current `cf target`.\n * - First try the user's *existing* CF session directly via cfEnvDirect (no re-auth).\n * - Only fall back to SAP + isolated re-auth if the error is classified as auth/session problem.\n * Explicit selector: Always full authenticated isolated path.\n *\n * This is the professional realization of the request:\n * When only an app is provided, the current CF target supplies org and space.\n * Auth/re-auth ONLY on session/unauthorize (per user feedback).\n */\nexport async function resolveAppBindings(\n rawSelector: string,\n options: ResolveBindingsOptions,\n): Promise<ResolvedBindings> {\n const selector = rawSelector.trim();\n if (!selector) {\n throw new CfHanaError(\"CONFIG\", \"App selector is required\");\n }\n\n let target: {\n selector: string;\n apiEndpoint: string;\n orgName: string;\n spaceName: string;\n appName: string;\n };\n\n const isBare = !selector.includes(\"/\");\n\n if (isBare) {\n // A bare app inherits region, org, and space from the current CF target.\n const current = await readCurrentCfTarget();\n if (!current) {\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 const displaySelector = current.regionKey\n ? formatCurrentCfAppSelector(current, selector)\n : `current/${current.orgName}/${current.spaceName}/${selector}`;\n target = {\n selector: displaySelector,\n apiEndpoint: current.apiEndpoint,\n orgName: current.orgName,\n spaceName: current.spaceName,\n appName: selector,\n };\n } else {\n // Explicit: region/org/space/app\n const parts = selector.split(\"/\").map((p) => p.trim());\n if (parts.length !== 4 || !parts[0] || !parts[1] || !parts[2] || !parts[3]) {\n throw new CfHanaError(\n \"CONFIG\",\n `Invalid selector \"${selector}\". Use region/org/space/app or a bare app name.`,\n );\n }\n const [regionKey, orgName, spaceName, appName] = parts as [string, string, string, string];\n const apiEndpoint = getApiEndpointForRegion(regionKey);\n if (!apiEndpoint) {\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 let normalizedApiEndpoint: string;\n try {\n normalizedApiEndpoint = normalizeSapCfApiEndpoint(apiEndpoint);\n } catch (error) {\n throw new CfHanaError(\"CONFIG\", errorMessageFromUnknown(error), { cause: error });\n }\n target = { selector, apiEndpoint: normalizedApiEndpoint, orgName, spaceName, appName };\n }\n\n let bindings: readonly HanaBinding[];\n const source: CredentialSource = \"live\";\n\n if (isBare) {\n // Preferred fast path for bare: use whatever CF context the user already has.\n // NO re-auth, NO new CF_HOME.\n try {\n const stdout = await cfEnvDirect(target.appName);\n bindings = extractHanaBindingsFromCfEnv(stdout);\n } catch (directError: unknown) {\n // Professional classification: only re-auth for real auth/session problems.\n let stderr = \"\";\n if (directError && typeof directError === \"object\") {\n const e = directError as { stderr?: unknown; message?: unknown };\n stderr =\n (typeof e.stderr === \"string\" ? e.stderr : \"\") ||\n (typeof e.message === \"string\" ? e.message : \"\");\n }\n const classified = classifyCfError(stderr);\n if (classified.isAuthError) {\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (!sap) {\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 const api = target.apiEndpoint;\n bindings = await withCfSession(async (ctx) => {\n await cfApi(api, ctx);\n await cfAuth(sap.email, sap.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n const stdout = await cfEnv(target.appName, ctx);\n return extractHanaBindingsFromCfEnv(stdout);\n });\n } else {\n // Not auth-related (e.g. app not present in current space)\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}\". ${stderr ? `Details: ${stderr}` : \"\"}`,\n { cause: directError },\n );\n }\n }\n } else {\n // Explicit selector always uses full authenticated isolated path\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (!sap) {\n throw new CredentialsNotFoundError(\n `SAP_EMAIL and SAP_PASSWORD are required to fetch HANA bindings for explicit selector \"${selector}\".`,\n );\n }\n const api = target.apiEndpoint;\n bindings = await withCfSession(async (ctx) => {\n await cfApi(api, ctx);\n await cfAuth(sap.email, sap.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n const stdout = await cfEnv(target.appName, ctx);\n return extractHanaBindingsFromCfEnv(stdout);\n });\n }\n\n if (bindings.length === 0) {\n throw new CredentialsNotFoundError(`App \"${target.selector}\" has no HANA service binding.`);\n }\n\n return {\n selector: target.selector,\n appName: target.appName,\n bindings,\n source,\n };\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 } 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 fakeExec(sql: string): DriverExecResult {\n const kind = classifyStatement(sql);\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 const upperSql = sql.toUpperCase();\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 {\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\n if (upperSql.includes(\"SYS.TABLE_COLUMNS\")) {\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\n if (upperSql.includes(\"MISSING_TABLE\") || upperSql.includes(\"MISSING_TABLES\")) {\n throw new QueryError(\"invalid table name: MISSING_TABLE\", { sqlState: \"42S02\" });\n }\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\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\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 if (sql.toUpperCase().includes(\"LOB_FIXTURE\")) {\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\n if (sql.toUpperCase().includes(\"DUMMY\")) {\n return {\n rows: [{ \"1\": 1 }],\n columns: [{ name: \"1\", typeName: \"INTEGER\" }],\n affectedRows: 0,\n };\n }\n\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\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 hasWhereClause(sql: string): boolean {\n return /\\bwhere\\b/i.test(maskIgnoredSqlText(sql));\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 return {\n kind,\n destructive: UNSCOPED_WRITE_KEYWORDS.has(keyword) && !hasWhereClause(sql),\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 or unscoped UPDATE/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 { QueryOptions, QueryResult, QueryRow, SqlParam } 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\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 selected = boundedRows(execResult.rows, 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 HanaClientInfo,\n PoolOptions,\n QueryOptions,\n QueryResult,\n QueryRow,\n SelectSpec,\n SqlParam,\n TableInfo,\n} from \"./types.js\";\n\nlet explainStatementCounter = 0;\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\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 ) {}\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 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: PoolOptions =\n options.pool === false ? { max: 1 } : (options.pool ?? {});\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 };\n return new HanaClient(new ConnectionPool(driver, config, poolOptions), info);\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 rows matched by an UPDATE or DELETE 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","join","appendFile","mkdir","rm","homedir","join","SAPTOOLS_DIR_NAME","CF_HANA_DIR_NAME","defaultSaptoolsRoot","skipQuotedText","skipLineComment","skipBlockComment"]}