pgserve 2.1.1 → 2.1.2
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/install.sh +123 -0
- package/package.json +1 -1
- package/src/cli-install.cjs +18 -1
- package/tests/cli-install.test.js +16 -0
package/install.sh
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# pgserve — Canonical PostgreSQL backbone installer
|
|
4
|
+
#
|
|
5
|
+
# Bootstraps a single shared pgserve instance under pm2 supervision. Used as
|
|
6
|
+
# a prerequisite by `omni/install.sh` and `genie/install.sh` so every
|
|
7
|
+
# automagik service on a host points at the same Postgres.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# curl -fsSL https://raw.githubusercontent.com/namastexlabs/pgserve/main/install.sh | bash
|
|
11
|
+
#
|
|
12
|
+
# With pinned version:
|
|
13
|
+
# PGSERVE_VERSION=^2.1.1 curl -fsSL .../install.sh | bash
|
|
14
|
+
#
|
|
15
|
+
# Local checkout:
|
|
16
|
+
# bash install.sh
|
|
17
|
+
#
|
|
18
|
+
# Idempotent — re-running is a no-op success when pgserve is already
|
|
19
|
+
# registered under pm2 with a healthy entry.
|
|
20
|
+
# ============================================================================
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
PGSERVE_VERSION="${PGSERVE_VERSION:-^2.1.0}"
|
|
24
|
+
|
|
25
|
+
# Colors (no-op when stdout isn't a tty)
|
|
26
|
+
if [[ -t 1 ]]; then
|
|
27
|
+
RED='\033[0;31m'
|
|
28
|
+
GREEN='\033[0;32m'
|
|
29
|
+
YELLOW='\033[1;33m'
|
|
30
|
+
BLUE='\033[0;34m'
|
|
31
|
+
CYAN='\033[0;36m'
|
|
32
|
+
BOLD='\033[1m'
|
|
33
|
+
NC='\033[0m'
|
|
34
|
+
else
|
|
35
|
+
RED='' GREEN='' YELLOW='' BLUE='' CYAN='' BOLD='' NC=''
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
info() { printf "${BLUE}ℹ${NC} %s\n" "$*"; }
|
|
39
|
+
ok() { printf "${GREEN}✓${NC} %s\n" "$*"; }
|
|
40
|
+
warn() { printf "${YELLOW}⚠${NC} %s\n" "$*"; }
|
|
41
|
+
fail() { printf "${RED}✗${NC} %s\n" "$*" >&2; exit 1; }
|
|
42
|
+
step() { printf "\n${BOLD}${CYAN}▸ %s${NC}\n" "$*"; }
|
|
43
|
+
|
|
44
|
+
has_cmd() { command -v "$1" >/dev/null 2>&1; }
|
|
45
|
+
|
|
46
|
+
# ============================================================================
|
|
47
|
+
# Prerequisites: bun + pm2
|
|
48
|
+
# ============================================================================
|
|
49
|
+
|
|
50
|
+
ensure_bun() {
|
|
51
|
+
if has_cmd bun; then
|
|
52
|
+
ok "bun $(bun --version 2>/dev/null || echo '?')"
|
|
53
|
+
return 0
|
|
54
|
+
fi
|
|
55
|
+
info "Installing bun (https://bun.sh)..."
|
|
56
|
+
curl -fsSL https://bun.sh/install | bash >/dev/null 2>&1 || fail "bun install failed — see https://bun.sh"
|
|
57
|
+
# Make bun available to the rest of this script without requiring a re-login.
|
|
58
|
+
export PATH="$HOME/.bun/bin:$PATH"
|
|
59
|
+
has_cmd bun || fail "bun installed but not on PATH — restart your shell and re-run."
|
|
60
|
+
ok "bun $(bun --version)"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
ensure_pm2() {
|
|
64
|
+
if has_cmd pm2; then
|
|
65
|
+
ok "pm2 $(pm2 --version 2>/dev/null || echo '?')"
|
|
66
|
+
return 0
|
|
67
|
+
fi
|
|
68
|
+
info "Installing pm2 (process supervisor)..."
|
|
69
|
+
bun add -g pm2 >/dev/null 2>&1 || fail "pm2 install failed — try: bun add -g pm2"
|
|
70
|
+
has_cmd pm2 || fail "pm2 installed but not on PATH — restart your shell and re-run."
|
|
71
|
+
ok "pm2 installed"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# ============================================================================
|
|
75
|
+
# pgserve binary + pm2 registration
|
|
76
|
+
# ============================================================================
|
|
77
|
+
|
|
78
|
+
ensure_pgserve_binary() {
|
|
79
|
+
# Probe via `pgserve port` (real subcommand). `pgserve --version` doesn't
|
|
80
|
+
# exist in 2.1.x — using it would false-negative and trigger a redundant
|
|
81
|
+
# reinstall every time install.sh runs.
|
|
82
|
+
if has_cmd pgserve && pgserve port >/dev/null 2>&1; then
|
|
83
|
+
ok "pgserve binary present (port $(pgserve port 2>/dev/null))"
|
|
84
|
+
return 0
|
|
85
|
+
fi
|
|
86
|
+
info "Installing pgserve@${PGSERVE_VERSION} globally..."
|
|
87
|
+
bun add -g "pgserve@${PGSERVE_VERSION}" >/dev/null 2>&1 \
|
|
88
|
+
|| fail "pgserve install failed — try: bun add -g pgserve@${PGSERVE_VERSION}"
|
|
89
|
+
has_cmd pgserve || fail "pgserve installed but not on PATH — restart your shell and re-run."
|
|
90
|
+
ok "pgserve $(pgserve port 2>/dev/null || echo '?')"
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
register_pgserve_pm2() {
|
|
94
|
+
info "Registering pgserve under pm2 (idempotent)..."
|
|
95
|
+
# `pgserve install` prints its own success/already-installed line and exits
|
|
96
|
+
# 0 in both cases. We pipe stderr through so any pm2 errors surface to the
|
|
97
|
+
# operator (the pm2-6.x --min-uptime breakage we hit on 2026-04-30 was
|
|
98
|
+
# invisible because stderr was being captured).
|
|
99
|
+
pgserve install || fail "pgserve install failed — see ~/.pgserve/logs/pgserve-error.log"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# ============================================================================
|
|
103
|
+
# Main
|
|
104
|
+
# ============================================================================
|
|
105
|
+
|
|
106
|
+
main() {
|
|
107
|
+
step "Installing canonical pgserve"
|
|
108
|
+
ensure_bun
|
|
109
|
+
ensure_pm2
|
|
110
|
+
ensure_pgserve_binary
|
|
111
|
+
register_pgserve_pm2
|
|
112
|
+
|
|
113
|
+
echo ""
|
|
114
|
+
ok "Canonical pgserve ready"
|
|
115
|
+
info "URL: $(pgserve url 2>/dev/null || echo '<run: pgserve url>')"
|
|
116
|
+
info "Port: $(pgserve port 2>/dev/null || echo '?')"
|
|
117
|
+
info "Logs: ~/.pgserve/logs/"
|
|
118
|
+
echo ""
|
|
119
|
+
info "Other automagik services on this host (omni, genie, ...) will share this pgserve."
|
|
120
|
+
echo ""
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
main "$@"
|
package/package.json
CHANGED
package/src/cli-install.cjs
CHANGED
|
@@ -179,7 +179,24 @@ function buildPm2StartArgs({ scriptPath, port, dataDir }) {
|
|
|
179
179
|
'--error',
|
|
180
180
|
logs.error,
|
|
181
181
|
'--',
|
|
182
|
-
|
|
182
|
+
// Foreground multi-tenant mode (`pgserve [options]`), NOT daemon mode.
|
|
183
|
+
//
|
|
184
|
+
// Daemon mode binds a unix control socket and requires libpq peers to
|
|
185
|
+
// authenticate via a fingerprint+token handshake (`pgserve daemon
|
|
186
|
+
// issue-token`). Downstream services that connect with a plain
|
|
187
|
+
// `postgres://` URL (omni, genie, anything that doesn't speak the
|
|
188
|
+
// fingerprint protocol) cannot reach a daemon-mode listener. We also
|
|
189
|
+
// observed live: `pgserve install` was passing `--port` to the daemon
|
|
190
|
+
// parser, which only accepts `--data | --ram | --log | --no-provision
|
|
191
|
+
// | --listen | --pgvector` — every install attempt crashed with
|
|
192
|
+
// `Unknown daemon option: --port` and pm2 burned its restart budget.
|
|
193
|
+
//
|
|
194
|
+
// Foreground mode (the default `pgserve [options]` invocation in
|
|
195
|
+
// postgres-server.js) accepts `--port`, auto-provisions databases on
|
|
196
|
+
// first connect, runs the cluster on multi-core hosts, and binds TCP
|
|
197
|
+
// on `127.0.0.1:<port>` with no auth dance — exactly what canonical
|
|
198
|
+
// pgserve consumers expect. Pass the same flags pgserve already
|
|
199
|
+
// documents in its own `pgserve --help` output.
|
|
183
200
|
'--port',
|
|
184
201
|
String(port),
|
|
185
202
|
'--data',
|
|
@@ -137,6 +137,22 @@ describe('pgserve install', () => {
|
|
|
137
137
|
expect(startCall).toContain('60000');
|
|
138
138
|
expect(startCall).toContain('--interpreter');
|
|
139
139
|
expect(startCall).toContain('none');
|
|
140
|
+
|
|
141
|
+
// pgserve install must launch the foreground multi-tenant server, NOT
|
|
142
|
+
// the daemon. Daemon mode rejects `--port` (it only accepts --data,
|
|
143
|
+
// --ram, --log, --no-provision, --listen, --pgvector) and its TCP
|
|
144
|
+
// listeners require fingerprint+token auth which downstream services
|
|
145
|
+
// (omni, genie) don't speak. Foreground mode binds plain TCP on
|
|
146
|
+
// 127.0.0.1:<port> with auto-provisioning. Lock that out:
|
|
147
|
+
expect(startCall).not.toContain('daemon');
|
|
148
|
+
// The script-arg handover (after `--`) must include `--port` so the
|
|
149
|
+
// foreground parser binds the right TCP port.
|
|
150
|
+
const dashDashIdx = startCall.indexOf('--');
|
|
151
|
+
const scriptArgs = startCall.slice(dashDashIdx + 1);
|
|
152
|
+
expect(scriptArgs).toContain('--port');
|
|
153
|
+
expect(scriptArgs).toContain('--data');
|
|
154
|
+
expect(scriptArgs).toContain('--log');
|
|
155
|
+
expect(scriptArgs).not.toContain('daemon');
|
|
140
156
|
});
|
|
141
157
|
|
|
142
158
|
test('second install is idempotent (no second pm2 start)', () => {
|