@crashlab/pg-mock 0.1.14 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -30,8 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ CrashlabUnsupportedPGFeature: () => CrashlabUnsupportedPGFeature,
33
34
  PgMock: () => PgMock,
34
- SimNodeUnsupportedPGFeature: () => SimNodeUnsupportedPGFeature,
35
35
  proto: () => protocol_exports
36
36
  });
37
37
  module.exports = __toCommonJS(index_exports);
@@ -144,10 +144,10 @@ function parseQueryMsg(data) {
144
144
  }
145
145
 
146
146
  // src/index.ts
147
- var SimNodeUnsupportedPGFeature = class extends Error {
147
+ var CrashlabUnsupportedPGFeature = class extends Error {
148
148
  constructor(detail) {
149
- super(`SimNode: Unsupported PostgreSQL feature: ${detail}`);
150
- this.name = "SimNodeUnsupportedPGFeature";
149
+ super(`Crashlab: Unsupported PostgreSQL feature: ${detail}`);
150
+ this.name = "CrashlabUnsupportedPGFeature";
151
151
  }
152
152
  };
153
153
  function createPGliteInstance() {
@@ -425,8 +425,8 @@ var PgMock = class {
425
425
  };
426
426
  // Annotate the CommonJS export names for ESM import in node:
427
427
  0 && (module.exports = {
428
+ CrashlabUnsupportedPGFeature,
428
429
  PgMock,
429
- SimNodeUnsupportedPGFeature,
430
430
  proto
431
431
  });
432
432
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/protocol.ts"],"sourcesContent":["import type { TcpMockHandler, TcpMockContext, TcpHandlerResult } from '@crashlab/tcp';\nimport * as proto from './protocol.js';\n\nexport class SimNodeUnsupportedPGFeature extends Error {\n constructor(detail: string) {\n super(`SimNode: Unsupported PostgreSQL feature: ${detail}`);\n this.name = 'SimNodeUnsupportedPGFeature';\n }\n}\n\n// ── PGlite helpers ────────────────────────────────────────────────────────────\n\n// Dynamically imported so the package remains optional at load time.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PGliteInstance = any;\n\nfunction createPGliteInstance(): Promise<PGliteInstance> {\n return import('@electric-sql/pglite').then(({ PGlite }) => new PGlite());\n}\n\n/** Infer a PostgreSQL command tag from the SQL statement and affected-row count. */\nfunction inferTag(sql: string, rowCount: number, affected?: number): string {\n const verb = sql.trim().split(/\\s+/)[0]?.toUpperCase() ?? '';\n switch (verb) {\n case 'SELECT': return `SELECT ${rowCount}`;\n case 'INSERT': return `INSERT 0 ${affected ?? rowCount}`;\n case 'UPDATE': return `UPDATE ${affected ?? rowCount}`;\n case 'DELETE': return `DELETE ${affected ?? rowCount}`;\n case 'CREATE': return 'CREATE TABLE';\n case 'DROP': return 'DROP TABLE';\n case 'BEGIN': return 'BEGIN';\n case 'COMMIT': return 'COMMIT';\n case 'ROLLBACK': return 'ROLLBACK';\n default: return verb;\n }\n}\n\n// ── PgConnection ──────────────────────────────────────────────────────────────\n\nclass PgConnection {\n private _phase: 'startup' | 'ready' = 'startup';\n private _txState: 'I' | 'T' | 'E' = 'I';\n private _buf: Buffer = Buffer.alloc(0);\n\n /** Prepared statements: statement name → SQL. '' = unnamed statement. */\n private _statements = new Map<string, string>();\n /** Bound portals: portal name → { sql, params }. '' = unnamed portal. */\n private _portals = new Map<string, { sql: string; params: string[] }>();\n\n constructor(private _pglite: Promise<PGliteInstance>) {}\n\n async processData(data: Buffer): Promise<Buffer> {\n this._buf = this._buf.length > 0 ? Buffer.concat([this._buf, data]) : data;\n\n // ── Startup / SSL handshake ───────────────────────────────────────────────\n if (this._phase === 'startup') {\n // SSL probe is exactly 8 bytes; startup message has a 4-byte length prefix\n if (this._buf.length < 4) return Buffer.alloc(0);\n const msgLen = this._buf.readInt32BE(0);\n if (this._buf.length < msgLen) return Buffer.alloc(0);\n\n const msg = this._buf.subarray(0, msgLen);\n this._buf = this._buf.subarray(msgLen);\n\n const parsed = proto.parseStartupMsg(msg);\n if ('isSSL' in parsed) return Buffer.from('N');\n this._phase = 'ready';\n return proto.startupResponse();\n }\n\n // ── Ready phase: consume complete framed messages ──────────────────────────\n const responses: Buffer[] = [];\n\n while (this._buf.length >= 5) {\n const msgType = String.fromCharCode(this._buf[0]);\n const msgLen = this._buf.readInt32BE(1); // includes self (4 bytes) but not type byte\n const totalLen = 1 + msgLen;\n if (this._buf.length < totalLen) break; // incomplete — wait for more data\n\n const payload = this._buf.subarray(5, totalLen);\n this._buf = this._buf.subarray(totalLen);\n\n // Simple Query ('Q')\n if (msgType === 'Q') {\n const nul = payload.indexOf(0);\n const sql = payload.toString('utf8', 0, nul >= 0 ? nul : payload.length);\n responses.push(await this._execQuery(sql));\n continue;\n }\n\n switch (msgType) {\n case 'P': { // Parse: statement_name\\0 + query\\0 + Int16(numParams) + ...\n const nameEnd = payload.indexOf(0);\n const stmtName = nameEnd > 0 ? payload.toString('utf8', 0, nameEnd) : '';\n const queryStart = nameEnd + 1;\n const queryEnd = payload.indexOf(0, queryStart);\n const sql = payload.toString('utf8', queryStart, queryEnd >= 0 ? queryEnd : payload.length);\n this._statements.set(stmtName, sql);\n responses.push(proto.parseComplete());\n break;\n }\n case 'B': { // Bind: portal\\0 + statement\\0 + formats + params + result_formats\n const { portal, statement, params } = this._parseBind(payload);\n const boundSql = this._statements.get(statement) ?? '';\n this._portals.set(portal, { sql: boundSql, params });\n responses.push(proto.bindComplete());\n break;\n }\n case 'D': { // Describe\n responses.push(proto.noData());\n break;\n }\n case 'E': { // Execute: portal\\0 + maxRows(Int32)\n const portalEnd = payload.indexOf(0);\n const portalName = portalEnd > 0 ? payload.toString('utf8', 0, portalEnd) : '';\n const bound = this._portals.get(portalName);\n if (bound && bound.sql) {\n const r = await this._execQueryWithParams(bound.sql, bound.params);\n responses.push(r);\n }\n break;\n }\n case 'S': { // Sync\n responses.push(proto.readyForQuery(this._txState));\n break;\n }\n case 'X': { // Terminate\n break;\n }\n default:\n // Silently ignore unknown message types\n break;\n }\n }\n\n return responses.length > 0 ? Buffer.concat(responses) : Buffer.alloc(0);\n }\n\n /** Parse a Bind message payload into portal, statement, and parameter values. */\n private _parseBind(payload: Buffer): { portal: string; statement: string; params: string[] } {\n let off = 0;\n // portal name \\0\n const portalEnd = payload.indexOf(0, off);\n const portal = portalEnd > off ? payload.toString('utf8', off, portalEnd) : '';\n off = portalEnd + 1;\n // statement name \\0\n const stmtEnd = payload.indexOf(0, off);\n const statement = stmtEnd > off ? payload.toString('utf8', off, stmtEnd) : '';\n off = stmtEnd + 1;\n // Int16 num format codes + format codes (skip)\n const numFormats = payload.readInt16BE(off); off += 2;\n off += numFormats * 2; // skip format codes\n // Int16 num params\n const numParams = payload.readInt16BE(off); off += 2;\n const params: string[] = [];\n for (let i = 0; i < numParams; i++) {\n const len = payload.readInt32BE(off); off += 4;\n if (len === -1) {\n params.push('NULL');\n } else {\n params.push(payload.toString('utf8', off, off + len));\n off += len;\n }\n }\n return { portal, statement, params };\n }\n\n /** Execute a parameterized query — substitutes $1, $2, … and runs via PGlite. */\n private async _execQueryWithParams(sql: string, params: string[]): Promise<Buffer> {\n const trimmed = sql.trim();\n const upper = trimmed.toUpperCase();\n\n if (upper === 'BEGIN') { this._txState = 'T'; return proto.commandComplete('BEGIN'); }\n if (upper === 'COMMIT') { this._txState = 'I'; return proto.commandComplete('COMMIT'); }\n if (upper === 'ROLLBACK') { this._txState = 'I'; return proto.commandComplete('ROLLBACK'); }\n\n const db = await this._pglite;\n try {\n // PGlite supports parameterized queries directly\n const result = await db.query(trimmed, params);\n const fields: Array<{ name: string }> = result.fields ?? [];\n const rows: Array<Record<string, unknown>> = result.rows ?? [];\n\n const bufs: Buffer[] = [];\n if (fields.length > 0) {\n bufs.push(proto.rowDescription(fields.map((f: { name: string }) => f.name)));\n for (const row of rows) {\n bufs.push(proto.dataRow(fields.map((f: { name: string }) => {\n const v = row[f.name];\n return v === null || v === undefined ? null : String(v);\n })));\n }\n }\n\n const tag = inferTag(trimmed, rows.length, result.affectedRows as number | undefined);\n bufs.push(proto.commandComplete(tag));\n return Buffer.concat(bufs);\n } catch (err) {\n return proto.errorResponse(err instanceof Error ? err.message : String(err));\n }\n }\n\n private async _execQuery(sql: string): Promise<Buffer> {\n const trimmed = sql.trim();\n const upper = trimmed.toUpperCase();\n\n if (upper === 'BEGIN') { this._txState = 'T'; return Buffer.concat([proto.commandComplete('BEGIN'), proto.readyForQuery('T')]); }\n if (upper === 'COMMIT') { this._txState = 'I'; return Buffer.concat([proto.commandComplete('COMMIT'), proto.readyForQuery('I')]); }\n if (upper === 'ROLLBACK') { this._txState = 'I'; return Buffer.concat([proto.commandComplete('ROLLBACK'), proto.readyForQuery('I')]); }\n\n const db = await this._pglite;\n try {\n const result = await db.query(trimmed);\n const fields: Array<{ name: string }> = result.fields ?? [];\n const rows: Array<Record<string, unknown>> = result.rows ?? [];\n\n const bufs: Buffer[] = [];\n\n if (fields.length > 0) {\n bufs.push(proto.rowDescription(fields.map((f: { name: string }) => f.name)));\n for (const row of rows) {\n bufs.push(proto.dataRow(fields.map((f: { name: string }) => {\n const v = row[f.name];\n return v === null || v === undefined ? null : String(v);\n })));\n }\n }\n\n const tag = inferTag(trimmed, rows.length, result.affectedRows as number | undefined);\n if (tag === 'BEGIN') this._txState = 'T';\n else if (tag === 'COMMIT' || tag === 'ROLLBACK') this._txState = 'I';\n\n bufs.push(proto.commandComplete(tag));\n bufs.push(proto.readyForQuery(this._txState));\n return Buffer.concat(bufs);\n } catch (err) {\n return Buffer.concat([\n proto.errorResponse(err instanceof Error ? err.message : String(err)),\n proto.readyForQuery(this._txState === 'T' ? 'E' : 'I'),\n ]);\n }\n }\n}\n\n// ── PgMock ────────────────────────────────────────────────────────────────────\n\nexport class PgMock {\n /** Shared PGlite instance (one per PgMock, lazy-initialised). */\n private _pglite: Promise<PGliteInstance>;\n /** Tracks all in-flight seed operations so ready() can await them. */\n private _seedPromise: Promise<void> = Promise.resolve();\n private _connections = new Map<number, PgConnection>();\n\n constructor() {\n this._pglite = createPGliteInstance();\n }\n\n /**\n * Resolves once PGlite is initialised AND all pending seedData() calls have\n * been mirrored into PGlite. Await this before making wire-protocol queries\n * in tests that call seedData().\n */\n async ready(): Promise<void> {\n await this._pglite;\n await this._seedPromise;\n }\n\n /**\n * Seed data directly into PGlite.\n * Creates a simple text-column table with the supplied rows.\n */\n seedData(table: string, rows: Array<Record<string, string | null>>): void {\n // Write directly to PGlite (no legacy sync store).\n this._seedPromise = this._seedPromise.then(() => this._seedPGlite(table, rows));\n }\n\n private async _seedPGlite(table: string, rows: Array<Record<string, string | null>>): Promise<void> {\n if (rows.length === 0) return;\n const db = await this._pglite;\n const cols = Object.keys(rows[0]);\n const colDefs = cols.map(c => `\"${c}\" TEXT`).join(', ');\n await db.exec(`CREATE TABLE IF NOT EXISTS \"${table}\" (${colDefs})`);\n for (const row of rows) {\n const vals = cols.map(c => row[c] === null ? 'NULL' : `'${String(row[c]).replace(/'/g, \"''\")}'`).join(', ');\n await db.exec(`INSERT INTO \"${table}\" (${cols.map(c => `\"${c}\"`).join(', ')}) VALUES (${vals})`);\n }\n }\n\n /**\n * Execute a raw SQL query against the embedded PGlite instance.\n * Returns rows as plain objects keyed by column name.\n */\n async query<T = Record<string, unknown>>(sql: string): Promise<{ rows: T[]; fields: Array<{ name: string }> }> {\n const db = await this._pglite;\n return db.query(sql) as Promise<{ rows: T[]; fields: Array<{ name: string }> }>;\n }\n\n createHandler(): TcpMockHandler {\n return async (data: Buffer, ctx: TcpMockContext): Promise<TcpHandlerResult> => {\n if (!this._connections.has(ctx.socketId)) {\n this._connections.set(ctx.socketId, new PgConnection(this._pglite));\n }\n return this._connections.get(ctx.socketId)!.processData(data);\n };\n }\n}\n\nexport { proto };\n","// PG wire protocol v3 encoding helpers\nconst int32 = (n: number): Buffer => { const b = Buffer.alloc(4); b.writeInt32BE(n); return b; };\nconst int16 = (n: number): Buffer => { const b = Buffer.alloc(2); b.writeInt16BE(n); return b; };\nconst cstr = (s: string): Buffer => Buffer.from(s + '\\0', 'utf8');\n\nfunction pgMsg(type: string, payload: Buffer): Buffer {\n return Buffer.concat([Buffer.from(type), int32(payload.length + 4), payload]);\n}\n\nexport const authOk = (): Buffer => pgMsg('R', int32(0));\nexport const paramStatus = (k: string, v: string): Buffer => pgMsg('S', Buffer.concat([cstr(k), cstr(v)]));\nexport const backendKeyData = (): Buffer => pgMsg('K', Buffer.concat([int32(1), int32(1)]));\nexport const readyForQuery = (s: 'I' | 'T' | 'E'): Buffer => pgMsg('Z', Buffer.from(s));\n\nexport function rowDescription(cols: string[]): Buffer {\n const parts: Buffer[] = [int16(cols.length)];\n for (const c of cols) {\n // name, tableOID, colAttrNum, typeOID(text=25), typeSize(-1), typeMod(-1), formatCode(0=text)\n const typeSizeBuf = Buffer.alloc(2);\n typeSizeBuf.writeInt16BE(-1);\n parts.push(cstr(c), int32(0), int16(0), int32(25), typeSizeBuf, int32(-1), int16(0));\n }\n return pgMsg('T', Buffer.concat(parts));\n}\n\nexport function dataRow(vals: (string | null)[]): Buffer {\n const parts: Buffer[] = [int16(vals.length)];\n for (const v of vals) {\n if (v === null) { parts.push(int32(-1)); }\n else { const b = Buffer.from(v, 'utf8'); parts.push(int32(b.length), b); }\n }\n return pgMsg('D', Buffer.concat(parts));\n}\n\nexport const commandComplete = (tag: string): Buffer => pgMsg('C', cstr(tag));\n\nexport function errorResponse(msg: string, code = '42000'): Buffer {\n return pgMsg('E', Buffer.concat([\n Buffer.from('S'), cstr('ERROR'),\n Buffer.from('C'), cstr(code),\n Buffer.from('M'), cstr(msg),\n Buffer.from([0]),\n ]));\n}\n\nexport function startupResponse(): Buffer {\n return Buffer.concat([\n authOk(),\n paramStatus('server_version', '15.0'),\n paramStatus('client_encoding', 'UTF8'),\n backendKeyData(),\n readyForQuery('I'),\n ]);\n}\n\n// Extended protocol response messages\nexport const parseComplete = (): Buffer => pgMsg('1', Buffer.alloc(0));\nexport const bindComplete = (): Buffer => pgMsg('2', Buffer.alloc(0));\nexport const noData = (): Buffer => pgMsg('n', Buffer.alloc(0));\n\n/**\n * Extract the portal name from an Execute message payload so that\n * PgConnection can look up the prepared SQL. Returns empty string\n * (unnamed portal) when no explicit portal name was given.\n */\nexport function parseExecuteMsg(payload: Buffer): string {\n // Execute: portal-name\\0 + maxRows(Int32)\n const nul = payload.indexOf(0);\n return nul > 0 ? payload.toString('utf8', 0, nul) : '';\n}\n\nexport function parseStartupMsg(data: Buffer): { isSSL: boolean } | { user: string; database: string } {\n if (data.length >= 8 && data.readInt32BE(4) === 80877103) return { isSSL: true };\n let off = 8;\n const params: Record<string, string> = {};\n while (off < data.length - 1) {\n const kEnd = data.indexOf(0, off); if (kEnd < 0) break;\n const key = data.toString('utf8', off, kEnd); off = kEnd + 1;\n const vEnd = data.indexOf(0, off); if (vEnd < 0) break;\n params[key] = data.toString('utf8', off, vEnd); off = vEnd + 1;\n }\n return { user: params.user ?? 'unknown', database: params.database ?? 'unknown' };\n}\n\nexport function parseQueryMsg(data: Buffer): string {\n // 'Q' + Int32 length + query\\0\n const nul = data.indexOf(0, 5);\n return data.toString('utf8', 5, nul >= 0 ? nul : data.length);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/protocol.ts"],"sourcesContent":["import type { TcpMockHandler, TcpMockContext, TcpHandlerResult } from '@crashlab/tcp';\nimport * as proto from './protocol.js';\n\nexport class CrashlabUnsupportedPGFeature extends Error {\n constructor(detail: string) {\n super(`Crashlab: Unsupported PostgreSQL feature: ${detail}`);\n this.name = 'CrashlabUnsupportedPGFeature';\n }\n}\n\n// ── PGlite helpers ────────────────────────────────────────────────────────────\n\n// Dynamically imported so the package remains optional at load time.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PGliteInstance = any;\n\nfunction createPGliteInstance(): Promise<PGliteInstance> {\n return import('@electric-sql/pglite').then(({ PGlite }) => new PGlite());\n}\n\n/** Infer a PostgreSQL command tag from the SQL statement and affected-row count. */\nfunction inferTag(sql: string, rowCount: number, affected?: number): string {\n const verb = sql.trim().split(/\\s+/)[0]?.toUpperCase() ?? '';\n switch (verb) {\n case 'SELECT': return `SELECT ${rowCount}`;\n case 'INSERT': return `INSERT 0 ${affected ?? rowCount}`;\n case 'UPDATE': return `UPDATE ${affected ?? rowCount}`;\n case 'DELETE': return `DELETE ${affected ?? rowCount}`;\n case 'CREATE': return 'CREATE TABLE';\n case 'DROP': return 'DROP TABLE';\n case 'BEGIN': return 'BEGIN';\n case 'COMMIT': return 'COMMIT';\n case 'ROLLBACK': return 'ROLLBACK';\n default: return verb;\n }\n}\n\n// ── PgConnection ──────────────────────────────────────────────────────────────\n\nclass PgConnection {\n private _phase: 'startup' | 'ready' = 'startup';\n private _txState: 'I' | 'T' | 'E' = 'I';\n private _buf: Buffer = Buffer.alloc(0);\n\n /** Prepared statements: statement name → SQL. '' = unnamed statement. */\n private _statements = new Map<string, string>();\n /** Bound portals: portal name → { sql, params }. '' = unnamed portal. */\n private _portals = new Map<string, { sql: string; params: string[] }>();\n\n constructor(private _pglite: Promise<PGliteInstance>) {}\n\n async processData(data: Buffer): Promise<Buffer> {\n this._buf = this._buf.length > 0 ? Buffer.concat([this._buf, data]) : data;\n\n // ── Startup / SSL handshake ───────────────────────────────────────────────\n if (this._phase === 'startup') {\n // SSL probe is exactly 8 bytes; startup message has a 4-byte length prefix\n if (this._buf.length < 4) return Buffer.alloc(0);\n const msgLen = this._buf.readInt32BE(0);\n if (this._buf.length < msgLen) return Buffer.alloc(0);\n\n const msg = this._buf.subarray(0, msgLen);\n this._buf = this._buf.subarray(msgLen);\n\n const parsed = proto.parseStartupMsg(msg);\n if ('isSSL' in parsed) return Buffer.from('N');\n this._phase = 'ready';\n return proto.startupResponse();\n }\n\n // ── Ready phase: consume complete framed messages ──────────────────────────\n const responses: Buffer[] = [];\n\n while (this._buf.length >= 5) {\n const msgType = String.fromCharCode(this._buf[0]);\n const msgLen = this._buf.readInt32BE(1); // includes self (4 bytes) but not type byte\n const totalLen = 1 + msgLen;\n if (this._buf.length < totalLen) break; // incomplete — wait for more data\n\n const payload = this._buf.subarray(5, totalLen);\n this._buf = this._buf.subarray(totalLen);\n\n // Simple Query ('Q')\n if (msgType === 'Q') {\n const nul = payload.indexOf(0);\n const sql = payload.toString('utf8', 0, nul >= 0 ? nul : payload.length);\n responses.push(await this._execQuery(sql));\n continue;\n }\n\n switch (msgType) {\n case 'P': { // Parse: statement_name\\0 + query\\0 + Int16(numParams) + ...\n const nameEnd = payload.indexOf(0);\n const stmtName = nameEnd > 0 ? payload.toString('utf8', 0, nameEnd) : '';\n const queryStart = nameEnd + 1;\n const queryEnd = payload.indexOf(0, queryStart);\n const sql = payload.toString('utf8', queryStart, queryEnd >= 0 ? queryEnd : payload.length);\n this._statements.set(stmtName, sql);\n responses.push(proto.parseComplete());\n break;\n }\n case 'B': { // Bind: portal\\0 + statement\\0 + formats + params + result_formats\n const { portal, statement, params } = this._parseBind(payload);\n const boundSql = this._statements.get(statement) ?? '';\n this._portals.set(portal, { sql: boundSql, params });\n responses.push(proto.bindComplete());\n break;\n }\n case 'D': { // Describe\n responses.push(proto.noData());\n break;\n }\n case 'E': { // Execute: portal\\0 + maxRows(Int32)\n const portalEnd = payload.indexOf(0);\n const portalName = portalEnd > 0 ? payload.toString('utf8', 0, portalEnd) : '';\n const bound = this._portals.get(portalName);\n if (bound && bound.sql) {\n const r = await this._execQueryWithParams(bound.sql, bound.params);\n responses.push(r);\n }\n break;\n }\n case 'S': { // Sync\n responses.push(proto.readyForQuery(this._txState));\n break;\n }\n case 'X': { // Terminate\n break;\n }\n default:\n // Silently ignore unknown message types\n break;\n }\n }\n\n return responses.length > 0 ? Buffer.concat(responses) : Buffer.alloc(0);\n }\n\n /** Parse a Bind message payload into portal, statement, and parameter values. */\n private _parseBind(payload: Buffer): { portal: string; statement: string; params: string[] } {\n let off = 0;\n // portal name \\0\n const portalEnd = payload.indexOf(0, off);\n const portal = portalEnd > off ? payload.toString('utf8', off, portalEnd) : '';\n off = portalEnd + 1;\n // statement name \\0\n const stmtEnd = payload.indexOf(0, off);\n const statement = stmtEnd > off ? payload.toString('utf8', off, stmtEnd) : '';\n off = stmtEnd + 1;\n // Int16 num format codes + format codes (skip)\n const numFormats = payload.readInt16BE(off); off += 2;\n off += numFormats * 2; // skip format codes\n // Int16 num params\n const numParams = payload.readInt16BE(off); off += 2;\n const params: string[] = [];\n for (let i = 0; i < numParams; i++) {\n const len = payload.readInt32BE(off); off += 4;\n if (len === -1) {\n params.push('NULL');\n } else {\n params.push(payload.toString('utf8', off, off + len));\n off += len;\n }\n }\n return { portal, statement, params };\n }\n\n /** Execute a parameterized query — substitutes $1, $2, … and runs via PGlite. */\n private async _execQueryWithParams(sql: string, params: string[]): Promise<Buffer> {\n const trimmed = sql.trim();\n const upper = trimmed.toUpperCase();\n\n if (upper === 'BEGIN') { this._txState = 'T'; return proto.commandComplete('BEGIN'); }\n if (upper === 'COMMIT') { this._txState = 'I'; return proto.commandComplete('COMMIT'); }\n if (upper === 'ROLLBACK') { this._txState = 'I'; return proto.commandComplete('ROLLBACK'); }\n\n const db = await this._pglite;\n try {\n // PGlite supports parameterized queries directly\n const result = await db.query(trimmed, params);\n const fields: Array<{ name: string }> = result.fields ?? [];\n const rows: Array<Record<string, unknown>> = result.rows ?? [];\n\n const bufs: Buffer[] = [];\n if (fields.length > 0) {\n bufs.push(proto.rowDescription(fields.map((f: { name: string }) => f.name)));\n for (const row of rows) {\n bufs.push(proto.dataRow(fields.map((f: { name: string }) => {\n const v = row[f.name];\n return v === null || v === undefined ? null : String(v);\n })));\n }\n }\n\n const tag = inferTag(trimmed, rows.length, result.affectedRows as number | undefined);\n bufs.push(proto.commandComplete(tag));\n return Buffer.concat(bufs);\n } catch (err) {\n return proto.errorResponse(err instanceof Error ? err.message : String(err));\n }\n }\n\n private async _execQuery(sql: string): Promise<Buffer> {\n const trimmed = sql.trim();\n const upper = trimmed.toUpperCase();\n\n if (upper === 'BEGIN') { this._txState = 'T'; return Buffer.concat([proto.commandComplete('BEGIN'), proto.readyForQuery('T')]); }\n if (upper === 'COMMIT') { this._txState = 'I'; return Buffer.concat([proto.commandComplete('COMMIT'), proto.readyForQuery('I')]); }\n if (upper === 'ROLLBACK') { this._txState = 'I'; return Buffer.concat([proto.commandComplete('ROLLBACK'), proto.readyForQuery('I')]); }\n\n const db = await this._pglite;\n try {\n const result = await db.query(trimmed);\n const fields: Array<{ name: string }> = result.fields ?? [];\n const rows: Array<Record<string, unknown>> = result.rows ?? [];\n\n const bufs: Buffer[] = [];\n\n if (fields.length > 0) {\n bufs.push(proto.rowDescription(fields.map((f: { name: string }) => f.name)));\n for (const row of rows) {\n bufs.push(proto.dataRow(fields.map((f: { name: string }) => {\n const v = row[f.name];\n return v === null || v === undefined ? null : String(v);\n })));\n }\n }\n\n const tag = inferTag(trimmed, rows.length, result.affectedRows as number | undefined);\n if (tag === 'BEGIN') this._txState = 'T';\n else if (tag === 'COMMIT' || tag === 'ROLLBACK') this._txState = 'I';\n\n bufs.push(proto.commandComplete(tag));\n bufs.push(proto.readyForQuery(this._txState));\n return Buffer.concat(bufs);\n } catch (err) {\n return Buffer.concat([\n proto.errorResponse(err instanceof Error ? err.message : String(err)),\n proto.readyForQuery(this._txState === 'T' ? 'E' : 'I'),\n ]);\n }\n }\n}\n\n// ── PgMock ────────────────────────────────────────────────────────────────────\n\nexport class PgMock {\n /** Shared PGlite instance (one per PgMock, lazy-initialised). */\n private _pglite: Promise<PGliteInstance>;\n /** Tracks all in-flight seed operations so ready() can await them. */\n private _seedPromise: Promise<void> = Promise.resolve();\n private _connections = new Map<number, PgConnection>();\n\n constructor() {\n this._pglite = createPGliteInstance();\n }\n\n /**\n * Resolves once PGlite is initialised AND all pending seedData() calls have\n * been mirrored into PGlite. Await this before making wire-protocol queries\n * in tests that call seedData().\n */\n async ready(): Promise<void> {\n await this._pglite;\n await this._seedPromise;\n }\n\n /**\n * Seed data directly into PGlite.\n * Creates a simple text-column table with the supplied rows.\n */\n seedData(table: string, rows: Array<Record<string, string | null>>): void {\n // Write directly to PGlite (no legacy sync store).\n this._seedPromise = this._seedPromise.then(() => this._seedPGlite(table, rows));\n }\n\n private async _seedPGlite(table: string, rows: Array<Record<string, string | null>>): Promise<void> {\n if (rows.length === 0) return;\n const db = await this._pglite;\n const cols = Object.keys(rows[0]);\n const colDefs = cols.map(c => `\"${c}\" TEXT`).join(', ');\n await db.exec(`CREATE TABLE IF NOT EXISTS \"${table}\" (${colDefs})`);\n for (const row of rows) {\n const vals = cols.map(c => row[c] === null ? 'NULL' : `'${String(row[c]).replace(/'/g, \"''\")}'`).join(', ');\n await db.exec(`INSERT INTO \"${table}\" (${cols.map(c => `\"${c}\"`).join(', ')}) VALUES (${vals})`);\n }\n }\n\n /**\n * Execute a raw SQL query against the embedded PGlite instance.\n * Returns rows as plain objects keyed by column name.\n */\n async query<T = Record<string, unknown>>(sql: string): Promise<{ rows: T[]; fields: Array<{ name: string }> }> {\n const db = await this._pglite;\n return db.query(sql) as Promise<{ rows: T[]; fields: Array<{ name: string }> }>;\n }\n\n createHandler(): TcpMockHandler {\n return async (data: Buffer, ctx: TcpMockContext): Promise<TcpHandlerResult> => {\n if (!this._connections.has(ctx.socketId)) {\n this._connections.set(ctx.socketId, new PgConnection(this._pglite));\n }\n return this._connections.get(ctx.socketId)!.processData(data);\n };\n }\n}\n\nexport { proto };\n","// PG wire protocol v3 encoding helpers\nconst int32 = (n: number): Buffer => { const b = Buffer.alloc(4); b.writeInt32BE(n); return b; };\nconst int16 = (n: number): Buffer => { const b = Buffer.alloc(2); b.writeInt16BE(n); return b; };\nconst cstr = (s: string): Buffer => Buffer.from(s + '\\0', 'utf8');\n\nfunction pgMsg(type: string, payload: Buffer): Buffer {\n return Buffer.concat([Buffer.from(type), int32(payload.length + 4), payload]);\n}\n\nexport const authOk = (): Buffer => pgMsg('R', int32(0));\nexport const paramStatus = (k: string, v: string): Buffer => pgMsg('S', Buffer.concat([cstr(k), cstr(v)]));\nexport const backendKeyData = (): Buffer => pgMsg('K', Buffer.concat([int32(1), int32(1)]));\nexport const readyForQuery = (s: 'I' | 'T' | 'E'): Buffer => pgMsg('Z', Buffer.from(s));\n\nexport function rowDescription(cols: string[]): Buffer {\n const parts: Buffer[] = [int16(cols.length)];\n for (const c of cols) {\n // name, tableOID, colAttrNum, typeOID(text=25), typeSize(-1), typeMod(-1), formatCode(0=text)\n const typeSizeBuf = Buffer.alloc(2);\n typeSizeBuf.writeInt16BE(-1);\n parts.push(cstr(c), int32(0), int16(0), int32(25), typeSizeBuf, int32(-1), int16(0));\n }\n return pgMsg('T', Buffer.concat(parts));\n}\n\nexport function dataRow(vals: (string | null)[]): Buffer {\n const parts: Buffer[] = [int16(vals.length)];\n for (const v of vals) {\n if (v === null) { parts.push(int32(-1)); }\n else { const b = Buffer.from(v, 'utf8'); parts.push(int32(b.length), b); }\n }\n return pgMsg('D', Buffer.concat(parts));\n}\n\nexport const commandComplete = (tag: string): Buffer => pgMsg('C', cstr(tag));\n\nexport function errorResponse(msg: string, code = '42000'): Buffer {\n return pgMsg('E', Buffer.concat([\n Buffer.from('S'), cstr('ERROR'),\n Buffer.from('C'), cstr(code),\n Buffer.from('M'), cstr(msg),\n Buffer.from([0]),\n ]));\n}\n\nexport function startupResponse(): Buffer {\n return Buffer.concat([\n authOk(),\n paramStatus('server_version', '15.0'),\n paramStatus('client_encoding', 'UTF8'),\n backendKeyData(),\n readyForQuery('I'),\n ]);\n}\n\n// Extended protocol response messages\nexport const parseComplete = (): Buffer => pgMsg('1', Buffer.alloc(0));\nexport const bindComplete = (): Buffer => pgMsg('2', Buffer.alloc(0));\nexport const noData = (): Buffer => pgMsg('n', Buffer.alloc(0));\n\n/**\n * Extract the portal name from an Execute message payload so that\n * PgConnection can look up the prepared SQL. Returns empty string\n * (unnamed portal) when no explicit portal name was given.\n */\nexport function parseExecuteMsg(payload: Buffer): string {\n // Execute: portal-name\\0 + maxRows(Int32)\n const nul = payload.indexOf(0);\n return nul > 0 ? payload.toString('utf8', 0, nul) : '';\n}\n\nexport function parseStartupMsg(data: Buffer): { isSSL: boolean } | { user: string; database: string } {\n if (data.length >= 8 && data.readInt32BE(4) === 80877103) return { isSSL: true };\n let off = 8;\n const params: Record<string, string> = {};\n while (off < data.length - 1) {\n const kEnd = data.indexOf(0, off); if (kEnd < 0) break;\n const key = data.toString('utf8', off, kEnd); off = kEnd + 1;\n const vEnd = data.indexOf(0, off); if (vEnd < 0) break;\n params[key] = data.toString('utf8', off, vEnd); off = vEnd + 1;\n }\n return { user: params.user ?? 'unknown', database: params.database ?? 'unknown' };\n}\n\nexport function parseQueryMsg(data: Buffer): string {\n // 'Q' + Int32 length + query\\0\n const nul = data.indexOf(0, 5);\n return data.toString('utf8', 5, nul >= 0 ? nul : data.length);\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { TcpMockHandler } from '@crashlab/tcp';
2
2
  import * as proto from './protocol.js';
3
- export declare class SimNodeUnsupportedPGFeature extends Error {
3
+ export declare class CrashlabUnsupportedPGFeature extends Error {
4
4
  constructor(detail: string);
5
5
  }
6
6
  export declare class PgMock {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAoC,MAAM,eAAe,CAAC;AACtF,OAAO,KAAK,KAAK,MAAM,eAAe,CAAC;AAEvC,qBAAa,2BAA4B,SAAQ,KAAK;gBACxC,MAAM,EAAE,MAAM;CAI3B;AA8OD,qBAAa,MAAM;IACjB,iEAAiE;IACjE,OAAO,CAAC,OAAO,CAA0B;IACzC,sEAAsE;IACtE,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,YAAY,CAAmC;;IAMvD;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI;YAK3D,WAAW;IAYzB;;;OAGG;IACG,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IAK9G,aAAa,IAAI,cAAc;CAQhC;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAoC,MAAM,eAAe,CAAC;AACtF,OAAO,KAAK,KAAK,MAAM,eAAe,CAAC;AAEvC,qBAAa,4BAA6B,SAAQ,KAAK;gBACzC,MAAM,EAAE,MAAM;CAI3B;AA8OD,qBAAa,MAAM;IACjB,iEAAiE;IACjE,OAAO,CAAC,OAAO,CAA0B;IACzC,sEAAsE;IACtE,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,YAAY,CAAmC;;IAMvD;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI;YAK3D,WAAW;IAYzB;;;OAGG;IACG,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IAK9G,aAAa,IAAI,cAAc;CAQhC;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -112,10 +112,10 @@ function parseQueryMsg(data) {
112
112
  }
113
113
 
114
114
  // src/index.ts
115
- var SimNodeUnsupportedPGFeature = class extends Error {
115
+ var CrashlabUnsupportedPGFeature = class extends Error {
116
116
  constructor(detail) {
117
- super(`SimNode: Unsupported PostgreSQL feature: ${detail}`);
118
- this.name = "SimNodeUnsupportedPGFeature";
117
+ super(`Crashlab: Unsupported PostgreSQL feature: ${detail}`);
118
+ this.name = "CrashlabUnsupportedPGFeature";
119
119
  }
120
120
  };
121
121
  function createPGliteInstance() {
@@ -392,8 +392,8 @@ var PgMock = class {
392
392
  }
393
393
  };
394
394
  export {
395
+ CrashlabUnsupportedPGFeature,
395
396
  PgMock,
396
- SimNodeUnsupportedPGFeature,
397
397
  protocol_exports as proto
398
398
  };
399
399
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/protocol.ts","../src/index.ts"],"sourcesContent":["// PG wire protocol v3 encoding helpers\nconst int32 = (n: number): Buffer => { const b = Buffer.alloc(4); b.writeInt32BE(n); return b; };\nconst int16 = (n: number): Buffer => { const b = Buffer.alloc(2); b.writeInt16BE(n); return b; };\nconst cstr = (s: string): Buffer => Buffer.from(s + '\\0', 'utf8');\n\nfunction pgMsg(type: string, payload: Buffer): Buffer {\n return Buffer.concat([Buffer.from(type), int32(payload.length + 4), payload]);\n}\n\nexport const authOk = (): Buffer => pgMsg('R', int32(0));\nexport const paramStatus = (k: string, v: string): Buffer => pgMsg('S', Buffer.concat([cstr(k), cstr(v)]));\nexport const backendKeyData = (): Buffer => pgMsg('K', Buffer.concat([int32(1), int32(1)]));\nexport const readyForQuery = (s: 'I' | 'T' | 'E'): Buffer => pgMsg('Z', Buffer.from(s));\n\nexport function rowDescription(cols: string[]): Buffer {\n const parts: Buffer[] = [int16(cols.length)];\n for (const c of cols) {\n // name, tableOID, colAttrNum, typeOID(text=25), typeSize(-1), typeMod(-1), formatCode(0=text)\n const typeSizeBuf = Buffer.alloc(2);\n typeSizeBuf.writeInt16BE(-1);\n parts.push(cstr(c), int32(0), int16(0), int32(25), typeSizeBuf, int32(-1), int16(0));\n }\n return pgMsg('T', Buffer.concat(parts));\n}\n\nexport function dataRow(vals: (string | null)[]): Buffer {\n const parts: Buffer[] = [int16(vals.length)];\n for (const v of vals) {\n if (v === null) { parts.push(int32(-1)); }\n else { const b = Buffer.from(v, 'utf8'); parts.push(int32(b.length), b); }\n }\n return pgMsg('D', Buffer.concat(parts));\n}\n\nexport const commandComplete = (tag: string): Buffer => pgMsg('C', cstr(tag));\n\nexport function errorResponse(msg: string, code = '42000'): Buffer {\n return pgMsg('E', Buffer.concat([\n Buffer.from('S'), cstr('ERROR'),\n Buffer.from('C'), cstr(code),\n Buffer.from('M'), cstr(msg),\n Buffer.from([0]),\n ]));\n}\n\nexport function startupResponse(): Buffer {\n return Buffer.concat([\n authOk(),\n paramStatus('server_version', '15.0'),\n paramStatus('client_encoding', 'UTF8'),\n backendKeyData(),\n readyForQuery('I'),\n ]);\n}\n\n// Extended protocol response messages\nexport const parseComplete = (): Buffer => pgMsg('1', Buffer.alloc(0));\nexport const bindComplete = (): Buffer => pgMsg('2', Buffer.alloc(0));\nexport const noData = (): Buffer => pgMsg('n', Buffer.alloc(0));\n\n/**\n * Extract the portal name from an Execute message payload so that\n * PgConnection can look up the prepared SQL. Returns empty string\n * (unnamed portal) when no explicit portal name was given.\n */\nexport function parseExecuteMsg(payload: Buffer): string {\n // Execute: portal-name\\0 + maxRows(Int32)\n const nul = payload.indexOf(0);\n return nul > 0 ? payload.toString('utf8', 0, nul) : '';\n}\n\nexport function parseStartupMsg(data: Buffer): { isSSL: boolean } | { user: string; database: string } {\n if (data.length >= 8 && data.readInt32BE(4) === 80877103) return { isSSL: true };\n let off = 8;\n const params: Record<string, string> = {};\n while (off < data.length - 1) {\n const kEnd = data.indexOf(0, off); if (kEnd < 0) break;\n const key = data.toString('utf8', off, kEnd); off = kEnd + 1;\n const vEnd = data.indexOf(0, off); if (vEnd < 0) break;\n params[key] = data.toString('utf8', off, vEnd); off = vEnd + 1;\n }\n return { user: params.user ?? 'unknown', database: params.database ?? 'unknown' };\n}\n\nexport function parseQueryMsg(data: Buffer): string {\n // 'Q' + Int32 length + query\\0\n const nul = data.indexOf(0, 5);\n return data.toString('utf8', 5, nul >= 0 ? nul : data.length);\n}\n","import type { TcpMockHandler, TcpMockContext, TcpHandlerResult } from '@crashlab/tcp';\nimport * as proto from './protocol.js';\n\nexport class SimNodeUnsupportedPGFeature extends Error {\n constructor(detail: string) {\n super(`SimNode: Unsupported PostgreSQL feature: ${detail}`);\n this.name = 'SimNodeUnsupportedPGFeature';\n }\n}\n\n// ── PGlite helpers ────────────────────────────────────────────────────────────\n\n// Dynamically imported so the package remains optional at load time.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PGliteInstance = any;\n\nfunction createPGliteInstance(): Promise<PGliteInstance> {\n return import('@electric-sql/pglite').then(({ PGlite }) => new PGlite());\n}\n\n/** Infer a PostgreSQL command tag from the SQL statement and affected-row count. */\nfunction inferTag(sql: string, rowCount: number, affected?: number): string {\n const verb = sql.trim().split(/\\s+/)[0]?.toUpperCase() ?? '';\n switch (verb) {\n case 'SELECT': return `SELECT ${rowCount}`;\n case 'INSERT': return `INSERT 0 ${affected ?? rowCount}`;\n case 'UPDATE': return `UPDATE ${affected ?? rowCount}`;\n case 'DELETE': return `DELETE ${affected ?? rowCount}`;\n case 'CREATE': return 'CREATE TABLE';\n case 'DROP': return 'DROP TABLE';\n case 'BEGIN': return 'BEGIN';\n case 'COMMIT': return 'COMMIT';\n case 'ROLLBACK': return 'ROLLBACK';\n default: return verb;\n }\n}\n\n// ── PgConnection ──────────────────────────────────────────────────────────────\n\nclass PgConnection {\n private _phase: 'startup' | 'ready' = 'startup';\n private _txState: 'I' | 'T' | 'E' = 'I';\n private _buf: Buffer = Buffer.alloc(0);\n\n /** Prepared statements: statement name → SQL. '' = unnamed statement. */\n private _statements = new Map<string, string>();\n /** Bound portals: portal name → { sql, params }. '' = unnamed portal. */\n private _portals = new Map<string, { sql: string; params: string[] }>();\n\n constructor(private _pglite: Promise<PGliteInstance>) {}\n\n async processData(data: Buffer): Promise<Buffer> {\n this._buf = this._buf.length > 0 ? Buffer.concat([this._buf, data]) : data;\n\n // ── Startup / SSL handshake ───────────────────────────────────────────────\n if (this._phase === 'startup') {\n // SSL probe is exactly 8 bytes; startup message has a 4-byte length prefix\n if (this._buf.length < 4) return Buffer.alloc(0);\n const msgLen = this._buf.readInt32BE(0);\n if (this._buf.length < msgLen) return Buffer.alloc(0);\n\n const msg = this._buf.subarray(0, msgLen);\n this._buf = this._buf.subarray(msgLen);\n\n const parsed = proto.parseStartupMsg(msg);\n if ('isSSL' in parsed) return Buffer.from('N');\n this._phase = 'ready';\n return proto.startupResponse();\n }\n\n // ── Ready phase: consume complete framed messages ──────────────────────────\n const responses: Buffer[] = [];\n\n while (this._buf.length >= 5) {\n const msgType = String.fromCharCode(this._buf[0]);\n const msgLen = this._buf.readInt32BE(1); // includes self (4 bytes) but not type byte\n const totalLen = 1 + msgLen;\n if (this._buf.length < totalLen) break; // incomplete — wait for more data\n\n const payload = this._buf.subarray(5, totalLen);\n this._buf = this._buf.subarray(totalLen);\n\n // Simple Query ('Q')\n if (msgType === 'Q') {\n const nul = payload.indexOf(0);\n const sql = payload.toString('utf8', 0, nul >= 0 ? nul : payload.length);\n responses.push(await this._execQuery(sql));\n continue;\n }\n\n switch (msgType) {\n case 'P': { // Parse: statement_name\\0 + query\\0 + Int16(numParams) + ...\n const nameEnd = payload.indexOf(0);\n const stmtName = nameEnd > 0 ? payload.toString('utf8', 0, nameEnd) : '';\n const queryStart = nameEnd + 1;\n const queryEnd = payload.indexOf(0, queryStart);\n const sql = payload.toString('utf8', queryStart, queryEnd >= 0 ? queryEnd : payload.length);\n this._statements.set(stmtName, sql);\n responses.push(proto.parseComplete());\n break;\n }\n case 'B': { // Bind: portal\\0 + statement\\0 + formats + params + result_formats\n const { portal, statement, params } = this._parseBind(payload);\n const boundSql = this._statements.get(statement) ?? '';\n this._portals.set(portal, { sql: boundSql, params });\n responses.push(proto.bindComplete());\n break;\n }\n case 'D': { // Describe\n responses.push(proto.noData());\n break;\n }\n case 'E': { // Execute: portal\\0 + maxRows(Int32)\n const portalEnd = payload.indexOf(0);\n const portalName = portalEnd > 0 ? payload.toString('utf8', 0, portalEnd) : '';\n const bound = this._portals.get(portalName);\n if (bound && bound.sql) {\n const r = await this._execQueryWithParams(bound.sql, bound.params);\n responses.push(r);\n }\n break;\n }\n case 'S': { // Sync\n responses.push(proto.readyForQuery(this._txState));\n break;\n }\n case 'X': { // Terminate\n break;\n }\n default:\n // Silently ignore unknown message types\n break;\n }\n }\n\n return responses.length > 0 ? Buffer.concat(responses) : Buffer.alloc(0);\n }\n\n /** Parse a Bind message payload into portal, statement, and parameter values. */\n private _parseBind(payload: Buffer): { portal: string; statement: string; params: string[] } {\n let off = 0;\n // portal name \\0\n const portalEnd = payload.indexOf(0, off);\n const portal = portalEnd > off ? payload.toString('utf8', off, portalEnd) : '';\n off = portalEnd + 1;\n // statement name \\0\n const stmtEnd = payload.indexOf(0, off);\n const statement = stmtEnd > off ? payload.toString('utf8', off, stmtEnd) : '';\n off = stmtEnd + 1;\n // Int16 num format codes + format codes (skip)\n const numFormats = payload.readInt16BE(off); off += 2;\n off += numFormats * 2; // skip format codes\n // Int16 num params\n const numParams = payload.readInt16BE(off); off += 2;\n const params: string[] = [];\n for (let i = 0; i < numParams; i++) {\n const len = payload.readInt32BE(off); off += 4;\n if (len === -1) {\n params.push('NULL');\n } else {\n params.push(payload.toString('utf8', off, off + len));\n off += len;\n }\n }\n return { portal, statement, params };\n }\n\n /** Execute a parameterized query — substitutes $1, $2, … and runs via PGlite. */\n private async _execQueryWithParams(sql: string, params: string[]): Promise<Buffer> {\n const trimmed = sql.trim();\n const upper = trimmed.toUpperCase();\n\n if (upper === 'BEGIN') { this._txState = 'T'; return proto.commandComplete('BEGIN'); }\n if (upper === 'COMMIT') { this._txState = 'I'; return proto.commandComplete('COMMIT'); }\n if (upper === 'ROLLBACK') { this._txState = 'I'; return proto.commandComplete('ROLLBACK'); }\n\n const db = await this._pglite;\n try {\n // PGlite supports parameterized queries directly\n const result = await db.query(trimmed, params);\n const fields: Array<{ name: string }> = result.fields ?? [];\n const rows: Array<Record<string, unknown>> = result.rows ?? [];\n\n const bufs: Buffer[] = [];\n if (fields.length > 0) {\n bufs.push(proto.rowDescription(fields.map((f: { name: string }) => f.name)));\n for (const row of rows) {\n bufs.push(proto.dataRow(fields.map((f: { name: string }) => {\n const v = row[f.name];\n return v === null || v === undefined ? null : String(v);\n })));\n }\n }\n\n const tag = inferTag(trimmed, rows.length, result.affectedRows as number | undefined);\n bufs.push(proto.commandComplete(tag));\n return Buffer.concat(bufs);\n } catch (err) {\n return proto.errorResponse(err instanceof Error ? err.message : String(err));\n }\n }\n\n private async _execQuery(sql: string): Promise<Buffer> {\n const trimmed = sql.trim();\n const upper = trimmed.toUpperCase();\n\n if (upper === 'BEGIN') { this._txState = 'T'; return Buffer.concat([proto.commandComplete('BEGIN'), proto.readyForQuery('T')]); }\n if (upper === 'COMMIT') { this._txState = 'I'; return Buffer.concat([proto.commandComplete('COMMIT'), proto.readyForQuery('I')]); }\n if (upper === 'ROLLBACK') { this._txState = 'I'; return Buffer.concat([proto.commandComplete('ROLLBACK'), proto.readyForQuery('I')]); }\n\n const db = await this._pglite;\n try {\n const result = await db.query(trimmed);\n const fields: Array<{ name: string }> = result.fields ?? [];\n const rows: Array<Record<string, unknown>> = result.rows ?? [];\n\n const bufs: Buffer[] = [];\n\n if (fields.length > 0) {\n bufs.push(proto.rowDescription(fields.map((f: { name: string }) => f.name)));\n for (const row of rows) {\n bufs.push(proto.dataRow(fields.map((f: { name: string }) => {\n const v = row[f.name];\n return v === null || v === undefined ? null : String(v);\n })));\n }\n }\n\n const tag = inferTag(trimmed, rows.length, result.affectedRows as number | undefined);\n if (tag === 'BEGIN') this._txState = 'T';\n else if (tag === 'COMMIT' || tag === 'ROLLBACK') this._txState = 'I';\n\n bufs.push(proto.commandComplete(tag));\n bufs.push(proto.readyForQuery(this._txState));\n return Buffer.concat(bufs);\n } catch (err) {\n return Buffer.concat([\n proto.errorResponse(err instanceof Error ? err.message : String(err)),\n proto.readyForQuery(this._txState === 'T' ? 'E' : 'I'),\n ]);\n }\n }\n}\n\n// ── PgMock ────────────────────────────────────────────────────────────────────\n\nexport class PgMock {\n /** Shared PGlite instance (one per PgMock, lazy-initialised). */\n private _pglite: Promise<PGliteInstance>;\n /** Tracks all in-flight seed operations so ready() can await them. */\n private _seedPromise: Promise<void> = Promise.resolve();\n private _connections = new Map<number, PgConnection>();\n\n constructor() {\n this._pglite = createPGliteInstance();\n }\n\n /**\n * Resolves once PGlite is initialised AND all pending seedData() calls have\n * been mirrored into PGlite. Await this before making wire-protocol queries\n * in tests that call seedData().\n */\n async ready(): Promise<void> {\n await this._pglite;\n await this._seedPromise;\n }\n\n /**\n * Seed data directly into PGlite.\n * Creates a simple text-column table with the supplied rows.\n */\n seedData(table: string, rows: Array<Record<string, string | null>>): void {\n // Write directly to PGlite (no legacy sync store).\n this._seedPromise = this._seedPromise.then(() => this._seedPGlite(table, rows));\n }\n\n private async _seedPGlite(table: string, rows: Array<Record<string, string | null>>): Promise<void> {\n if (rows.length === 0) return;\n const db = await this._pglite;\n const cols = Object.keys(rows[0]);\n const colDefs = cols.map(c => `\"${c}\" TEXT`).join(', ');\n await db.exec(`CREATE TABLE IF NOT EXISTS \"${table}\" (${colDefs})`);\n for (const row of rows) {\n const vals = cols.map(c => row[c] === null ? 'NULL' : `'${String(row[c]).replace(/'/g, \"''\")}'`).join(', ');\n await db.exec(`INSERT INTO \"${table}\" (${cols.map(c => `\"${c}\"`).join(', ')}) VALUES (${vals})`);\n }\n }\n\n /**\n * Execute a raw SQL query against the embedded PGlite instance.\n * Returns rows as plain objects keyed by column name.\n */\n async query<T = Record<string, unknown>>(sql: string): Promise<{ rows: T[]; fields: Array<{ name: string }> }> {\n const db = await this._pglite;\n return db.query(sql) as Promise<{ rows: T[]; fields: Array<{ name: string }> }>;\n }\n\n createHandler(): TcpMockHandler {\n return async (data: Buffer, ctx: TcpMockContext): Promise<TcpHandlerResult> => {\n if (!this._connections.has(ctx.socketId)) {\n this._connections.set(ctx.socketId, new PgConnection(this._pglite));\n }\n return this._connections.get(ctx.socketId)!.processData(data);\n };\n }\n}\n\nexport { proto };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/protocol.ts","../src/index.ts"],"sourcesContent":["// PG wire protocol v3 encoding helpers\nconst int32 = (n: number): Buffer => { const b = Buffer.alloc(4); b.writeInt32BE(n); return b; };\nconst int16 = (n: number): Buffer => { const b = Buffer.alloc(2); b.writeInt16BE(n); return b; };\nconst cstr = (s: string): Buffer => Buffer.from(s + '\\0', 'utf8');\n\nfunction pgMsg(type: string, payload: Buffer): Buffer {\n return Buffer.concat([Buffer.from(type), int32(payload.length + 4), payload]);\n}\n\nexport const authOk = (): Buffer => pgMsg('R', int32(0));\nexport const paramStatus = (k: string, v: string): Buffer => pgMsg('S', Buffer.concat([cstr(k), cstr(v)]));\nexport const backendKeyData = (): Buffer => pgMsg('K', Buffer.concat([int32(1), int32(1)]));\nexport const readyForQuery = (s: 'I' | 'T' | 'E'): Buffer => pgMsg('Z', Buffer.from(s));\n\nexport function rowDescription(cols: string[]): Buffer {\n const parts: Buffer[] = [int16(cols.length)];\n for (const c of cols) {\n // name, tableOID, colAttrNum, typeOID(text=25), typeSize(-1), typeMod(-1), formatCode(0=text)\n const typeSizeBuf = Buffer.alloc(2);\n typeSizeBuf.writeInt16BE(-1);\n parts.push(cstr(c), int32(0), int16(0), int32(25), typeSizeBuf, int32(-1), int16(0));\n }\n return pgMsg('T', Buffer.concat(parts));\n}\n\nexport function dataRow(vals: (string | null)[]): Buffer {\n const parts: Buffer[] = [int16(vals.length)];\n for (const v of vals) {\n if (v === null) { parts.push(int32(-1)); }\n else { const b = Buffer.from(v, 'utf8'); parts.push(int32(b.length), b); }\n }\n return pgMsg('D', Buffer.concat(parts));\n}\n\nexport const commandComplete = (tag: string): Buffer => pgMsg('C', cstr(tag));\n\nexport function errorResponse(msg: string, code = '42000'): Buffer {\n return pgMsg('E', Buffer.concat([\n Buffer.from('S'), cstr('ERROR'),\n Buffer.from('C'), cstr(code),\n Buffer.from('M'), cstr(msg),\n Buffer.from([0]),\n ]));\n}\n\nexport function startupResponse(): Buffer {\n return Buffer.concat([\n authOk(),\n paramStatus('server_version', '15.0'),\n paramStatus('client_encoding', 'UTF8'),\n backendKeyData(),\n readyForQuery('I'),\n ]);\n}\n\n// Extended protocol response messages\nexport const parseComplete = (): Buffer => pgMsg('1', Buffer.alloc(0));\nexport const bindComplete = (): Buffer => pgMsg('2', Buffer.alloc(0));\nexport const noData = (): Buffer => pgMsg('n', Buffer.alloc(0));\n\n/**\n * Extract the portal name from an Execute message payload so that\n * PgConnection can look up the prepared SQL. Returns empty string\n * (unnamed portal) when no explicit portal name was given.\n */\nexport function parseExecuteMsg(payload: Buffer): string {\n // Execute: portal-name\\0 + maxRows(Int32)\n const nul = payload.indexOf(0);\n return nul > 0 ? payload.toString('utf8', 0, nul) : '';\n}\n\nexport function parseStartupMsg(data: Buffer): { isSSL: boolean } | { user: string; database: string } {\n if (data.length >= 8 && data.readInt32BE(4) === 80877103) return { isSSL: true };\n let off = 8;\n const params: Record<string, string> = {};\n while (off < data.length - 1) {\n const kEnd = data.indexOf(0, off); if (kEnd < 0) break;\n const key = data.toString('utf8', off, kEnd); off = kEnd + 1;\n const vEnd = data.indexOf(0, off); if (vEnd < 0) break;\n params[key] = data.toString('utf8', off, vEnd); off = vEnd + 1;\n }\n return { user: params.user ?? 'unknown', database: params.database ?? 'unknown' };\n}\n\nexport function parseQueryMsg(data: Buffer): string {\n // 'Q' + Int32 length + query\\0\n const nul = data.indexOf(0, 5);\n return data.toString('utf8', 5, nul >= 0 ? nul : data.length);\n}\n","import type { TcpMockHandler, TcpMockContext, TcpHandlerResult } from '@crashlab/tcp';\nimport * as proto from './protocol.js';\n\nexport class CrashlabUnsupportedPGFeature extends Error {\n constructor(detail: string) {\n super(`Crashlab: Unsupported PostgreSQL feature: ${detail}`);\n this.name = 'CrashlabUnsupportedPGFeature';\n }\n}\n\n// ── PGlite helpers ────────────────────────────────────────────────────────────\n\n// Dynamically imported so the package remains optional at load time.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PGliteInstance = any;\n\nfunction createPGliteInstance(): Promise<PGliteInstance> {\n return import('@electric-sql/pglite').then(({ PGlite }) => new PGlite());\n}\n\n/** Infer a PostgreSQL command tag from the SQL statement and affected-row count. */\nfunction inferTag(sql: string, rowCount: number, affected?: number): string {\n const verb = sql.trim().split(/\\s+/)[0]?.toUpperCase() ?? '';\n switch (verb) {\n case 'SELECT': return `SELECT ${rowCount}`;\n case 'INSERT': return `INSERT 0 ${affected ?? rowCount}`;\n case 'UPDATE': return `UPDATE ${affected ?? rowCount}`;\n case 'DELETE': return `DELETE ${affected ?? rowCount}`;\n case 'CREATE': return 'CREATE TABLE';\n case 'DROP': return 'DROP TABLE';\n case 'BEGIN': return 'BEGIN';\n case 'COMMIT': return 'COMMIT';\n case 'ROLLBACK': return 'ROLLBACK';\n default: return verb;\n }\n}\n\n// ── PgConnection ──────────────────────────────────────────────────────────────\n\nclass PgConnection {\n private _phase: 'startup' | 'ready' = 'startup';\n private _txState: 'I' | 'T' | 'E' = 'I';\n private _buf: Buffer = Buffer.alloc(0);\n\n /** Prepared statements: statement name → SQL. '' = unnamed statement. */\n private _statements = new Map<string, string>();\n /** Bound portals: portal name → { sql, params }. '' = unnamed portal. */\n private _portals = new Map<string, { sql: string; params: string[] }>();\n\n constructor(private _pglite: Promise<PGliteInstance>) {}\n\n async processData(data: Buffer): Promise<Buffer> {\n this._buf = this._buf.length > 0 ? Buffer.concat([this._buf, data]) : data;\n\n // ── Startup / SSL handshake ───────────────────────────────────────────────\n if (this._phase === 'startup') {\n // SSL probe is exactly 8 bytes; startup message has a 4-byte length prefix\n if (this._buf.length < 4) return Buffer.alloc(0);\n const msgLen = this._buf.readInt32BE(0);\n if (this._buf.length < msgLen) return Buffer.alloc(0);\n\n const msg = this._buf.subarray(0, msgLen);\n this._buf = this._buf.subarray(msgLen);\n\n const parsed = proto.parseStartupMsg(msg);\n if ('isSSL' in parsed) return Buffer.from('N');\n this._phase = 'ready';\n return proto.startupResponse();\n }\n\n // ── Ready phase: consume complete framed messages ──────────────────────────\n const responses: Buffer[] = [];\n\n while (this._buf.length >= 5) {\n const msgType = String.fromCharCode(this._buf[0]);\n const msgLen = this._buf.readInt32BE(1); // includes self (4 bytes) but not type byte\n const totalLen = 1 + msgLen;\n if (this._buf.length < totalLen) break; // incomplete — wait for more data\n\n const payload = this._buf.subarray(5, totalLen);\n this._buf = this._buf.subarray(totalLen);\n\n // Simple Query ('Q')\n if (msgType === 'Q') {\n const nul = payload.indexOf(0);\n const sql = payload.toString('utf8', 0, nul >= 0 ? nul : payload.length);\n responses.push(await this._execQuery(sql));\n continue;\n }\n\n switch (msgType) {\n case 'P': { // Parse: statement_name\\0 + query\\0 + Int16(numParams) + ...\n const nameEnd = payload.indexOf(0);\n const stmtName = nameEnd > 0 ? payload.toString('utf8', 0, nameEnd) : '';\n const queryStart = nameEnd + 1;\n const queryEnd = payload.indexOf(0, queryStart);\n const sql = payload.toString('utf8', queryStart, queryEnd >= 0 ? queryEnd : payload.length);\n this._statements.set(stmtName, sql);\n responses.push(proto.parseComplete());\n break;\n }\n case 'B': { // Bind: portal\\0 + statement\\0 + formats + params + result_formats\n const { portal, statement, params } = this._parseBind(payload);\n const boundSql = this._statements.get(statement) ?? '';\n this._portals.set(portal, { sql: boundSql, params });\n responses.push(proto.bindComplete());\n break;\n }\n case 'D': { // Describe\n responses.push(proto.noData());\n break;\n }\n case 'E': { // Execute: portal\\0 + maxRows(Int32)\n const portalEnd = payload.indexOf(0);\n const portalName = portalEnd > 0 ? payload.toString('utf8', 0, portalEnd) : '';\n const bound = this._portals.get(portalName);\n if (bound && bound.sql) {\n const r = await this._execQueryWithParams(bound.sql, bound.params);\n responses.push(r);\n }\n break;\n }\n case 'S': { // Sync\n responses.push(proto.readyForQuery(this._txState));\n break;\n }\n case 'X': { // Terminate\n break;\n }\n default:\n // Silently ignore unknown message types\n break;\n }\n }\n\n return responses.length > 0 ? Buffer.concat(responses) : Buffer.alloc(0);\n }\n\n /** Parse a Bind message payload into portal, statement, and parameter values. */\n private _parseBind(payload: Buffer): { portal: string; statement: string; params: string[] } {\n let off = 0;\n // portal name \\0\n const portalEnd = payload.indexOf(0, off);\n const portal = portalEnd > off ? payload.toString('utf8', off, portalEnd) : '';\n off = portalEnd + 1;\n // statement name \\0\n const stmtEnd = payload.indexOf(0, off);\n const statement = stmtEnd > off ? payload.toString('utf8', off, stmtEnd) : '';\n off = stmtEnd + 1;\n // Int16 num format codes + format codes (skip)\n const numFormats = payload.readInt16BE(off); off += 2;\n off += numFormats * 2; // skip format codes\n // Int16 num params\n const numParams = payload.readInt16BE(off); off += 2;\n const params: string[] = [];\n for (let i = 0; i < numParams; i++) {\n const len = payload.readInt32BE(off); off += 4;\n if (len === -1) {\n params.push('NULL');\n } else {\n params.push(payload.toString('utf8', off, off + len));\n off += len;\n }\n }\n return { portal, statement, params };\n }\n\n /** Execute a parameterized query — substitutes $1, $2, … and runs via PGlite. */\n private async _execQueryWithParams(sql: string, params: string[]): Promise<Buffer> {\n const trimmed = sql.trim();\n const upper = trimmed.toUpperCase();\n\n if (upper === 'BEGIN') { this._txState = 'T'; return proto.commandComplete('BEGIN'); }\n if (upper === 'COMMIT') { this._txState = 'I'; return proto.commandComplete('COMMIT'); }\n if (upper === 'ROLLBACK') { this._txState = 'I'; return proto.commandComplete('ROLLBACK'); }\n\n const db = await this._pglite;\n try {\n // PGlite supports parameterized queries directly\n const result = await db.query(trimmed, params);\n const fields: Array<{ name: string }> = result.fields ?? [];\n const rows: Array<Record<string, unknown>> = result.rows ?? [];\n\n const bufs: Buffer[] = [];\n if (fields.length > 0) {\n bufs.push(proto.rowDescription(fields.map((f: { name: string }) => f.name)));\n for (const row of rows) {\n bufs.push(proto.dataRow(fields.map((f: { name: string }) => {\n const v = row[f.name];\n return v === null || v === undefined ? null : String(v);\n })));\n }\n }\n\n const tag = inferTag(trimmed, rows.length, result.affectedRows as number | undefined);\n bufs.push(proto.commandComplete(tag));\n return Buffer.concat(bufs);\n } catch (err) {\n return proto.errorResponse(err instanceof Error ? err.message : String(err));\n }\n }\n\n private async _execQuery(sql: string): Promise<Buffer> {\n const trimmed = sql.trim();\n const upper = trimmed.toUpperCase();\n\n if (upper === 'BEGIN') { this._txState = 'T'; return Buffer.concat([proto.commandComplete('BEGIN'), proto.readyForQuery('T')]); }\n if (upper === 'COMMIT') { this._txState = 'I'; return Buffer.concat([proto.commandComplete('COMMIT'), proto.readyForQuery('I')]); }\n if (upper === 'ROLLBACK') { this._txState = 'I'; return Buffer.concat([proto.commandComplete('ROLLBACK'), proto.readyForQuery('I')]); }\n\n const db = await this._pglite;\n try {\n const result = await db.query(trimmed);\n const fields: Array<{ name: string }> = result.fields ?? [];\n const rows: Array<Record<string, unknown>> = result.rows ?? [];\n\n const bufs: Buffer[] = [];\n\n if (fields.length > 0) {\n bufs.push(proto.rowDescription(fields.map((f: { name: string }) => f.name)));\n for (const row of rows) {\n bufs.push(proto.dataRow(fields.map((f: { name: string }) => {\n const v = row[f.name];\n return v === null || v === undefined ? null : String(v);\n })));\n }\n }\n\n const tag = inferTag(trimmed, rows.length, result.affectedRows as number | undefined);\n if (tag === 'BEGIN') this._txState = 'T';\n else if (tag === 'COMMIT' || tag === 'ROLLBACK') this._txState = 'I';\n\n bufs.push(proto.commandComplete(tag));\n bufs.push(proto.readyForQuery(this._txState));\n return Buffer.concat(bufs);\n } catch (err) {\n return Buffer.concat([\n proto.errorResponse(err instanceof Error ? err.message : String(err)),\n proto.readyForQuery(this._txState === 'T' ? 'E' : 'I'),\n ]);\n }\n }\n}\n\n// ── PgMock ────────────────────────────────────────────────────────────────────\n\nexport class PgMock {\n /** Shared PGlite instance (one per PgMock, lazy-initialised). */\n private _pglite: Promise<PGliteInstance>;\n /** Tracks all in-flight seed operations so ready() can await them. */\n private _seedPromise: Promise<void> = Promise.resolve();\n private _connections = new Map<number, PgConnection>();\n\n constructor() {\n this._pglite = createPGliteInstance();\n }\n\n /**\n * Resolves once PGlite is initialised AND all pending seedData() calls have\n * been mirrored into PGlite. Await this before making wire-protocol queries\n * in tests that call seedData().\n */\n async ready(): Promise<void> {\n await this._pglite;\n await this._seedPromise;\n }\n\n /**\n * Seed data directly into PGlite.\n * Creates a simple text-column table with the supplied rows.\n */\n seedData(table: string, rows: Array<Record<string, string | null>>): void {\n // Write directly to PGlite (no legacy sync store).\n this._seedPromise = this._seedPromise.then(() => this._seedPGlite(table, rows));\n }\n\n private async _seedPGlite(table: string, rows: Array<Record<string, string | null>>): Promise<void> {\n if (rows.length === 0) return;\n const db = await this._pglite;\n const cols = Object.keys(rows[0]);\n const colDefs = cols.map(c => `\"${c}\" TEXT`).join(', ');\n await db.exec(`CREATE TABLE IF NOT EXISTS \"${table}\" (${colDefs})`);\n for (const row of rows) {\n const vals = cols.map(c => row[c] === null ? 'NULL' : `'${String(row[c]).replace(/'/g, \"''\")}'`).join(', ');\n await db.exec(`INSERT INTO \"${table}\" (${cols.map(c => `\"${c}\"`).join(', ')}) VALUES (${vals})`);\n }\n }\n\n /**\n * Execute a raw SQL query against the embedded PGlite instance.\n * Returns rows as plain objects keyed by column name.\n */\n async query<T = Record<string, unknown>>(sql: string): Promise<{ rows: T[]; fields: Array<{ name: string }> }> {\n const db = await this._pglite;\n return db.query(sql) as Promise<{ rows: T[]; fields: Array<{ name: string }> }>;\n }\n\n createHandler(): TcpMockHandler {\n return async (data: Buffer, ctx: TcpMockContext): Promise<TcpHandlerResult> => {\n if (!this._connections.has(ctx.socketId)) {\n this._connections.set(ctx.socketId, new PgConnection(this._pglite));\n }\n return this._connections.get(ctx.socketId)!.processData(data);\n };\n }\n}\n\nexport { proto };\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crashlab/pg-mock",
3
- "version": "0.1.14",
3
+ "version": "1.0.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",