pgserve 2.1.2 → 2.1.3

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.
@@ -132,6 +132,7 @@ function parseDaemonArgs(daemonArgs) {
132
132
  autoProvision: true,
133
133
  tcpListens: [],
134
134
  enablePgvector: false,
135
+ maxConnections: null,
135
136
  };
136
137
  for (let i = 0; i < daemonArgs.length; i++) {
137
138
  const arg = daemonArgs[i];
@@ -156,6 +157,21 @@ function parseDaemonArgs(daemonArgs) {
156
157
  case '--pgvector':
157
158
  opts.enablePgvector = true;
158
159
  break;
160
+ case '--max-connections': {
161
+ // Accept the same flag the foreground/router mode takes so callers
162
+ // (genie's `getOrStartDaemon`, anything that spawns `pgserve daemon`
163
+ // with a tuned cap) can override the postmaster's `max_connections`.
164
+ // The `PgserveDaemon` constructor already honors `options.maxConnections`
165
+ // (see src/daemon.js — defaults to 1000); we just plumb it through.
166
+ const raw = daemonArgs[++i];
167
+ const parsed = Number.parseInt(raw, 10);
168
+ if (!Number.isFinite(parsed) || parsed <= 0) {
169
+ console.error(`--max-connections: expected a positive integer, got "${raw}"`);
170
+ process.exit(1);
171
+ }
172
+ opts.maxConnections = parsed;
173
+ break;
174
+ }
159
175
  case '--help':
160
176
  console.log(`
161
177
  pgserve daemon — singleton control-socket mode
@@ -167,13 +183,14 @@ USAGE:
167
183
  pgserve daemon revoke-token <id>
168
184
 
169
185
  OPTIONS:
170
- --data <path> Persistent data directory (default: in-memory)
171
- --ram Use /dev/shm storage (Linux only)
172
- --log <level> Log level: error|warn|info|debug (default: info)
173
- --no-provision Disable auto-provisioning of databases
174
- --listen [host:]port Bind opt-in TCP listener (repeatable)
175
- --pgvector Auto-enable pgvector extension on new databases
176
- --help Show this help
186
+ --data <path> Persistent data directory (default: in-memory)
187
+ --ram Use /dev/shm storage (Linux only)
188
+ --log <level> Log level: error|warn|info|debug (default: info)
189
+ --no-provision Disable auto-provisioning of databases
190
+ --listen [host:]port Bind opt-in TCP listener (repeatable)
191
+ --pgvector Auto-enable pgvector extension on new databases
192
+ --max-connections <n> Override the postmaster's max_connections (default: 1000)
193
+ --help Show this help
177
194
 
178
195
  The daemon binds $XDG_RUNTIME_DIR/pgserve/control.sock (fallback /tmp/pgserve/control.sock).
179
196
  A second invocation while the first is running exits with "already running".
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgserve",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "description": "Embedded PostgreSQL server with true concurrent connections - zero config, auto-provision databases",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Integration tests for `pgserve daemon` argv parsing.
3
+ *
4
+ * `parseDaemonArgs` lives inside `bin/postgres-server.js` (the script
5
+ * entry point) and isn't exported, so we exercise it via subprocess
6
+ * invocations of the wrapper. Each test runs in <100ms — they only ask
7
+ * the daemon to print help or reject an invalid argument; no real
8
+ * postgres backend is started.
9
+ *
10
+ * Background: every recent CLI-flag mismatch between callers and
11
+ * `pgserve daemon` exited the daemon child with code 1 immediately,
12
+ * surfacing upstream as the unhelpful "pgserve v2 daemon exited before
13
+ * binding …" error. These tests pin the daemon's accepted flag set
14
+ * explicitly so the next mismatch fails CI here, not at runtime.
15
+ */
16
+
17
+ import { spawnSync } from 'node:child_process';
18
+ import { join } from 'node:path';
19
+ import { fileURLToPath } from 'node:url';
20
+ import { describe, expect, test } from 'bun:test';
21
+
22
+ const REPO_ROOT = join(fileURLToPath(import.meta.url), '..', '..');
23
+ const PGSERVE_BIN = join(REPO_ROOT, 'bin', 'pgserve-wrapper.cjs');
24
+
25
+ function runDaemon(args, timeoutMs = 3000) {
26
+ return spawnSync('node', [PGSERVE_BIN, 'daemon', ...args], {
27
+ encoding: 'utf-8',
28
+ timeout: timeoutMs,
29
+ stdio: ['ignore', 'pipe', 'pipe'],
30
+ });
31
+ }
32
+
33
+ describe('pgserve daemon — argv parser', () => {
34
+ test('--help lists every flag the daemon accepts', () => {
35
+ const result = runDaemon(['--help']);
36
+ expect(result.status).toBe(0);
37
+ const help = result.stdout;
38
+ // Every flag the parser accepts must appear in --help so callers
39
+ // (and the next operator running `pgserve daemon --help`) discover them.
40
+ expect(help).toContain('--data');
41
+ expect(help).toContain('--ram');
42
+ expect(help).toContain('--log');
43
+ expect(help).toContain('--no-provision');
44
+ expect(help).toContain('--listen');
45
+ expect(help).toContain('--pgvector');
46
+ expect(help).toContain('--max-connections');
47
+ expect(help).toContain('--help');
48
+ });
49
+
50
+ test('--max-connections accepts a positive integer (no "Unknown option" error)', () => {
51
+ // Use a bogus --data path so the daemon never actually starts postgres
52
+ // — the parser runs, accepts --max-connections, then PgserveDaemon
53
+ // tries to start and fails on the missing/invalid data dir. We only
54
+ // care that the parser doesn't reject the flag.
55
+ const result = runDaemon(['--data', '/nonexistent/pgserve-test-dir', '--max-connections', '5000', '--log', 'error']);
56
+ // The daemon may exit non-zero because the data dir is invalid, but
57
+ // it MUST NOT exit with "Unknown daemon option" — that's the
58
+ // pre-fix behavior we're guarding against.
59
+ const stderr = result.stderr ?? '';
60
+ expect(stderr).not.toContain('Unknown daemon option: --max-connections');
61
+ });
62
+
63
+ test('--max-connections rejects non-numeric values with a clear error', () => {
64
+ const result = runDaemon(['--max-connections', 'abc']);
65
+ expect(result.status).toBe(1);
66
+ expect(result.stderr).toContain('--max-connections: expected a positive integer');
67
+ });
68
+
69
+ test('--max-connections rejects zero / negative values', () => {
70
+ const zero = runDaemon(['--max-connections', '0']);
71
+ expect(zero.status).toBe(1);
72
+ expect(zero.stderr).toContain('--max-connections: expected a positive integer');
73
+
74
+ const negative = runDaemon(['--max-connections', '-50']);
75
+ expect(negative.status).toBe(1);
76
+ expect(negative.stderr).toContain('--max-connections: expected a positive integer');
77
+ });
78
+
79
+ test('unknown flags still exit 1 with the documented "Unknown daemon option" error', () => {
80
+ // Sanity: the parser hasn't become permissive. Genuinely unknown
81
+ // flags must still error out so callers learn about the mismatch.
82
+ const result = runDaemon(['--definitely-not-a-flag']);
83
+ expect(result.status).toBe(1);
84
+ expect(result.stderr).toContain('Unknown daemon option: --definitely-not-a-flag');
85
+ });
86
+ });