PostgreSQL Wire Protocol Parser/Serializer
pg-protocol is a foundational TypeScript library that implements the PostgreSQL client/server binary wire protocol. It provides low-level parsing and serialization capabilities for PostgreSQL messages, serving as a core internal dependency for the popular `node-postgres` client library. The version specified for this entry is 1.13.0 (though npm's 'latest' tag currently points to 1.12.0), and its release cadence is tied closely to the development of `node-postgres` itself, meaning updates are often driven by new PostgreSQL features or performance enhancements needed by the higher-level client. Its key differentiator is its precise, TypeScript-driven implementation of the PostgreSQL protocol specification, enabling robust and type-safe interaction at the binary level. While it can be used independently for specialized tasks like building custom PostgreSQL proxies or analytics tools, its primary role is to abstract away the intricate protocol details for database client developers.
Common errors
-
Cannot find module 'pg-protocol' or its corresponding type declarations.
cause The `pg-protocol` package is not installed, or the import path is incorrect, especially if trying to import specific nested modules.fixEnsure `pg-protocol` is installed via `npm install pg-protocol` or `yarn add pg-protocol`. If importing specific sub-paths (e.g., for messages), verify the exact path from the package's type definitions or source. -
TypeError: Serializer.query is not a function
cause Attempting to call a method that doesn't exist or using an outdated API, potentially due to `pg-protocol`'s internal nature and API instability for direct consumers.fixConsult the `pg-protocol` source code or TypeScript declarations for the exact methods and their signatures available in your installed version. The internal API might change more frequently than `node-postgres`'s public API. Ensure you are importing the correct class (e.g., `Serializer`) and using its methods as defined in the current version.
Warnings
- gotcha pg-protocol is primarily an internal module of the `node-postgres` ecosystem. Its API is low-level and not designed for direct public consumption. Using it directly may expose you to internal changes that are not considered breaking within `node-postgres`'s public API, but could break your direct usage.
- breaking With `node-postgres` v8.x (which utilizes `pg-protocol` internally), the default behavior for SSL connections changed. Previously, `rejectUnauthorized` defaulted to `false`, allowing self-signed certificates without explicit configuration. It now defaults to `true` for improved security.
- gotcha PostgreSQL 18 introduces Wire Protocol 3.2, which includes enhanced security features like 256-bit cancel request keys. While `pg-protocol` aims to support new protocol features, adopting them requires updates to both the client (e.g., `node-postgres`) and the server. Older clients or `pg-protocol` versions might not fully utilize newer protocol features.
Install
-
npm install pg-protocol -
yarn add pg-protocol -
pnpm add pg-protocol
Imports
- Parser
const Parser = require('pg-protocol').Parser;import { Parser } from 'pg-protocol'; - Serializer
const { Serializer } = require('pg-protocol');import { Serializer } from 'pg-protocol'; - Message
import type { Message } from 'pg-protocol'; - Query
import { Query } from 'pg-protocol/dist/messages';
Quickstart
import { Parser, Serializer } from 'pg-protocol';
import { Query, ReadyForQueryMessage, BackendMessageCode } from 'pg-protocol/dist/messages';
// 1. Simulate an incoming 'ReadyForQuery' message from the server
// (Type 'Z' for ReadyForQuery, length, transaction status 'I' for idle)
const readyForQueryBuffer = Buffer.from([BackendMessageCode.ReadyForQuery, 0, 0, 0, 5, 'I'.charCodeAt(0)]);
const parser = new Parser();
parser.parse(readyForQueryBuffer);
// In a real scenario, you'd listen to 'message' events
// For this example, we'll manually check the parsed queue
let parsedMessage: ReadyForQueryMessage | undefined;
while (true) {
const msg = parser.shift();
if (msg) {
if (msg.name === 'ReadyForQuery') {
parsedMessage = msg as ReadyForQueryMessage;
console.log(`Parsed ReadyForQuery: Transaction Status = ${parsedMessage.transactionStatus}`);
break;
}
} else {
break;
}
}
if (!parsedMessage) {
console.error('Failed to parse ReadyForQuery message.');
}
// 2. Serialize an outgoing 'Query' message to the server
const query = 'SELECT 1 + 1 AS solution;';
const serializer = new Serializer();
// The Query message expects a string and can be serialized directly
const queryMessage = new Query(query);
const serializedBuffer = serializer.query(query);
console.log(`
Original Query: ${query}`);
console.log('Serialized Query Buffer (first 20 bytes):', serializedBuffer.toString('hex').substring(0, 40), '...');
console.log(`Buffer length: ${serializedBuffer.length} bytes`);
// Example: Basic structure of a 'Query' message buffer
// Message type 'Q', then length including length itself, then query string + null terminator
const expectedHeader = Buffer.from([0x51, 0x00, 0x00, 0x00, (query.length + 5) >> 8, 0x00, 0x00, 0x00, (query.length + 5) & 0xFF]);
// Note: Actual serialization includes the string and null terminator.
// This is a simplified check.