Skip to content

Commit a9f2b24

Browse files
committed
Identify Serverless driver connections
1 parent ecce07e commit a9f2b24

8 files changed

Lines changed: 1178 additions & 1122 deletions

File tree

build.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/usr/bin/env bash
22
set -e
33

4+
PACKAGE_VERSION=$(node -p "require('./package.json').version")
5+
46
# if nothing modified, stop (`touch src` to force build)
57
find src -newer index.js | read || exit 0
68

@@ -20,6 +22,7 @@ npx esbuild src/index.ts \
2022
--keep-names \
2123
--inject:src/shims/shims.js \
2224
--define:BUNDLE_EXT=\"js\" \
25+
--define:PACKAGE_VERSION=\"$PACKAGE_VERSION\" \
2326
--target=es2020 \
2427
--outfile=index.js \
2528
$DEBUG_ARG $MINIFY_ARG
@@ -32,6 +35,7 @@ npx esbuild src/index.ts \
3235
--keep-names \
3336
--inject:src/shims/shims.js \
3437
--define:BUNDLE_EXT=\"mjs\" \
38+
--define:PACKAGE_VERSION=\"$PACKAGE_VERSION\" \
3539
--target=es2020 \
3640
--banner:js='/* @ts-self-types="./index.d.mts" */' \
3741
--outfile=index.mjs \

index.js

Lines changed: 563 additions & 562 deletions
Large diffs are not rendered by default.

index.mjs

Lines changed: 560 additions & 559 deletions
Large diffs are not rendered by default.

src/client.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Client, Connection, type ClientConfig } from 'pg';
22
import { Socket } from './shims/net';
33
import { warnIfBrowser } from './utils';
4+
import { PACKAGE_URL } from './packageInfo';
45

56
export declare interface NeonClient {
67
connection: Connection & {
@@ -25,7 +26,11 @@ export class NeonClient extends Client {
2526
}
2627

2728
constructor(public config?: string | ClientConfig) {
28-
super(config);
29+
super(
30+
typeof config === 'string'
31+
? { connectionString: config, fallback_application_name: PACKAGE_URL }
32+
: { fallback_application_name: PACKAGE_URL, ...config },
33+
);
2934
}
3035

3136
override connect(): Promise<void>;

src/httpQuery.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {
2828
} from './httpTypes';
2929
import { SqlTemplate, UnsafeRawSql } from './sqlTemplate';
3030
import { warnIfBrowser } from './utils';
31+
import { PACKAGE_URL } from './packageInfo';
3132

3233
import { Socket as neonConfig } from './shims/net';
3334

@@ -351,6 +352,7 @@ export function neon<
351352
'Neon-Connection-String': connectionString,
352353
'Neon-Raw-Text-Output': 'true', // because we do our own parsing with node-postgres
353354
'Neon-Array-Mode': 'true', // this saves data and post-processing even if we return objects, not arrays
355+
'Neon-Client-Info': PACKAGE_URL,
354356
};
355357

356358
// --- add auth token to headers ---

src/packageInfo.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare const PACKAGE_VERSION: string;
2+
3+
export const PACKAGE_URL = `pkg:npm/%40neondatabase/serverless@${PACKAGE_VERSION}`;

tests/cli/http.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
type FullQueryResults,
99
} from '@neondatabase/serverless'; // see package.json: this points to 'file:.'
1010
import { sampleQueries } from './sampleQueries';
11+
import packageMetadata from '../../package.json';
1112

1213
const DATABASE_URL = process.env.VITE_NEON_DB_URL!;
1314
const sql = neon(DATABASE_URL);
@@ -205,6 +206,31 @@ test('custom fetch', async () => {
205206
}
206207
});
207208

209+
test('sends the package URL with HTTP queries', async () => {
210+
const prevFetchFunction = neonConfig.fetchFunction;
211+
try {
212+
const fn = vi.fn(async () =>
213+
Response.json({
214+
fields: [],
215+
rows: [],
216+
command: 'SELECT',
217+
rowCount: 0,
218+
}),
219+
);
220+
neonConfig.fetchFunction = fn;
221+
222+
const mockedSql = neon('postgres://user@example.com/database');
223+
await mockedSql`SELECT`;
224+
225+
expect(fn).toHaveBeenCalledOnce();
226+
expect(fn.mock.calls[0][1]?.headers).toMatchObject({
227+
'Neon-Client-Info': `pkg:npm/%40neondatabase/serverless@${packageMetadata.version}`,
228+
});
229+
} finally {
230+
neonConfig.fetchFunction = prevFetchFunction;
231+
}
232+
});
233+
208234
test('errors match WebSocket query errors', async () => {
209235
const q = 'SELECT 123 WHERE x';
210236

tests/cli/ws.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Pool as PgPool, type QueryResult } from 'pg';
33
import * as subtls from 'subtls';
44
import { sampleQueries } from './sampleQueries';
55
import { ISRGX1Cert } from './subtlsCert';
6+
import packageMetadata from '../../package.json';
67
import {
78
neon,
89
neonConfig,
@@ -34,6 +35,19 @@ const DB_POOLER_URL = process.env.VITE_NEON_DB_POOLER_URL!;
3435

3536
const pgPool = new PgPool({ connectionString: DB_DIRECT_URL });
3637

38+
test('uses the package URL as the default application name', () => {
39+
const expected = `pkg:npm/%40neondatabase/serverless@${packageMetadata.version}`;
40+
41+
const defaultClient = new WsClient('postgres://user@example.com/database');
42+
expect(defaultClient.getStartupConf().application_name).toBe(expected);
43+
44+
const namedClient = new WsClient({
45+
connectionString: 'postgres://user@example.com/database',
46+
application_name: 'custom-client',
47+
});
48+
expect(namedClient.getStartupConf().application_name).toBe('custom-client');
49+
});
50+
3751
describe.each([
3852
{
3953
DB_URL: DB_DIRECT_URL,

0 commit comments

Comments
 (0)