Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,35 @@ Its value is a string containing zero or more certificates in PEM format.

Default: `""` (the empty string).

#### `isNeonLocal: boolean`

Set `isNeonLocal` to `true` when connecting to a Neon Local proxy instance. This flag enables specific optimizations and behaviors for local development environments.

**Key behaviors when `isNeonLocal` is `true`:**

1. **Automatic endpoint configuration**: The SQL fetch endpoint automatically uses the host and port from your connection string instead of the Neon cloud API endpoints.
2. **Protocol handling**: Uses `https://` when `useSecureWebSocket` is `true`, `http://` when `false`.
3. **Port handling**: Standard ports (443 for HTTPS, 80 for HTTP) are omitted from URLs; custom ports are included.
4. **Automatic credential injection**: Credentials from the connection string are automatically sent as WebSocket headers for the Neon Local proxy to inject into the PostgreSQL protocol.

For example:

````javascript
```javascript
import { neonConfig, Client } from '@neondatabase/serverless';

// Enable Neon Local mode
neonConfig.isNeonLocal = true;

// Connection string credentials are automatically extracted and sent as headers
const client = new Client('postgresql://postgres:password@localhost:5432/mydb');
await client.connect();
// WebSocket headers: X-Neon-User: postgres, X-Neon-Password: password, X-Neon-Database: mydb
````

**Note**: This feature requires a custom `webSocketConstructor` (like the `ws` library in Node.js) that supports headers. Browser WebSocket APIs don't support custom headers, but Neon Local typically runs in server-side environments.
Default: `false`.

#### `pipelineTLS: boolean`

**Only when using experimental pure-JS encryption**, the driver will pipeline the SSL request message and TLS Client Hello if `pipelineTLS` is set to `true`. Currently, this is only supported by Neon database hosts, and will fail when communicating with an ordinary Postgres or pgbouncer back-end.
Expand Down
37 changes: 37 additions & 0 deletions index.d.mts
Original file line number Diff line number Diff line change
Expand Up @@ -441,11 +441,17 @@ export declare interface NeonConfig {
pipelineTLS: boolean;
disableSNI: boolean;
disableWarningInBrowsers: boolean;
isNeonLocal: boolean;
}

export declare class neonConfig extends EventEmitter {
static defaults: NeonConfig;
static opts: Partial<NeonConfig>;
/**
* Set connection string credentials for automatic injection in Neon Local mode.
* This is called automatically by the Client class when isNeonLocal is true.
*/
setConnectionCredentials(credentials: NeonLocalCredentials): void;
/**
* **Experimentally**, when `poolQueryViaFetch` is `true`, and no listeners
* for the `"connect"`, `"acquire"`, `"release"` or `"remove"` events are set
Expand Down Expand Up @@ -619,6 +625,17 @@ export declare class neonConfig extends EventEmitter {
static set rootCerts(newValue: NeonConfig['rootCerts']);
get rootCerts(): NeonConfig["rootCerts"];
set rootCerts(newValue: NeonConfig['rootCerts']);
/**
* Set `isNeonLocal` to `true` when connecting to a Neon Local proxy instance.
* This flag can be used by the driver to enable specific optimizations and
* behaviors when working with local development environments.
*
* Default: `false`.
*/
static get isNeonLocal(): NeonConfig["isNeonLocal"];
static set isNeonLocal(newValue: NeonConfig['isNeonLocal']);
get isNeonLocal(): NeonConfig["isNeonLocal"];
set isNeonLocal(newValue: NeonConfig['isNeonLocal']);
wsProxyAddrForHost(host: string, port: number): string;
connecting: boolean;
pending: boolean;
Expand Down Expand Up @@ -665,6 +682,12 @@ export declare class NeonDbError extends Error {
constructor(message: string);
}

declare interface NeonLocalCredentials {
user?: string;
password?: string;
database?: string;
}

export declare interface NeonQueryFunction<ArrayMode extends boolean, FullResults extends boolean> {
(strings: TemplateStringsArray, ...params: any[]): NeonQueryPromise<ArrayMode, FullResults, FullResults extends true ? FullQueryResults<ArrayMode> : QueryRows<ArrayMode>>;
/**
Expand Down Expand Up @@ -797,6 +820,8 @@ export declare interface PoolClient extends PoolClient_2 {

export { PoolConfig }

export declare function processQueryResult(rawResults: any, { arrayMode, fullResults, types: customTypes }: ProcessQueryResultOptions): any;

export declare interface ProcessQueryResultOptions {
arrayMode: boolean;
fullResults: boolean;
Expand Down Expand Up @@ -913,6 +938,18 @@ export declare interface WebSocketLike {
close(code?: number, reason?: string): void;
send(data: any): void;
addEventListener(type: 'open' | 'message' | 'close' | 'error', listener: (this: WebSocketLike, ev: any) => any, options?: any): void;
onopen?: (this: WebSocketLike) => void;
onmessage?: (this: WebSocketLike, ev: {
data: any;
}) => void;
onerror?: (this: WebSocketLike, ev: {
error?: any;
message?: string;
}) => void;
onclose?: (this: WebSocketLike, ev: {
code: number;
reason?: string;
}) => void;
}

export declare class WebSocketReadQueue extends ReadQueue {
Expand Down
37 changes: 37 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,11 +441,17 @@ export declare interface NeonConfig {
pipelineTLS: boolean;
disableSNI: boolean;
disableWarningInBrowsers: boolean;
isNeonLocal: boolean;
}

export declare class neonConfig extends EventEmitter {
static defaults: NeonConfig;
static opts: Partial<NeonConfig>;
/**
* Set connection string credentials for automatic injection in Neon Local mode.
* This is called automatically by the Client class when isNeonLocal is true.
*/
setConnectionCredentials(credentials: NeonLocalCredentials): void;
/**
* **Experimentally**, when `poolQueryViaFetch` is `true`, and no listeners
* for the `"connect"`, `"acquire"`, `"release"` or `"remove"` events are set
Expand Down Expand Up @@ -619,6 +625,17 @@ export declare class neonConfig extends EventEmitter {
static set rootCerts(newValue: NeonConfig['rootCerts']);
get rootCerts(): NeonConfig["rootCerts"];
set rootCerts(newValue: NeonConfig['rootCerts']);
/**
* Set `isNeonLocal` to `true` when connecting to a Neon Local proxy instance.
* This flag can be used by the driver to enable specific optimizations and
* behaviors when working with local development environments.
*
* Default: `false`.
*/
static get isNeonLocal(): NeonConfig["isNeonLocal"];
static set isNeonLocal(newValue: NeonConfig['isNeonLocal']);
get isNeonLocal(): NeonConfig["isNeonLocal"];
set isNeonLocal(newValue: NeonConfig['isNeonLocal']);
wsProxyAddrForHost(host: string, port: number): string;
connecting: boolean;
pending: boolean;
Expand Down Expand Up @@ -665,6 +682,12 @@ export declare class NeonDbError extends Error {
constructor(message: string);
}

declare interface NeonLocalCredentials {
user?: string;
password?: string;
database?: string;
}

export declare interface NeonQueryFunction<ArrayMode extends boolean, FullResults extends boolean> {
(strings: TemplateStringsArray, ...params: any[]): NeonQueryPromise<ArrayMode, FullResults, FullResults extends true ? FullQueryResults<ArrayMode> : QueryRows<ArrayMode>>;
/**
Expand Down Expand Up @@ -797,6 +820,8 @@ export declare interface PoolClient extends PoolClient_2 {

export { PoolConfig }

export declare function processQueryResult(rawResults: any, { arrayMode, fullResults, types: customTypes }: ProcessQueryResultOptions): any;

export declare interface ProcessQueryResultOptions {
arrayMode: boolean;
fullResults: boolean;
Expand Down Expand Up @@ -913,6 +938,18 @@ export declare interface WebSocketLike {
close(code?: number, reason?: string): void;
send(data: any): void;
addEventListener(type: 'open' | 'message' | 'close' | 'error', listener: (this: WebSocketLike, ev: any) => any, options?: any): void;
onopen?: (this: WebSocketLike) => void;
onmessage?: (this: WebSocketLike, ev: {
data: any;
}) => void;
onerror?: (this: WebSocketLike, ev: {
error?: any;
message?: string;
}) => void;
onclose?: (this: WebSocketLike, ev: {
code: number;
reason?: string;
}) => void;
}

export declare class WebSocketReadQueue extends ReadQueue {
Expand Down
Loading