Skip to content

v3.0.0#13

Merged
tsvillain merged 12 commits into
devfrom
3.0.0
May 21, 2026
Merged

v3.0.0#13
tsvillain merged 12 commits into
devfrom
3.0.0

Conversation

@tsvillain
Copy link
Copy Markdown
Owner

No description provided.

tsvillain added 12 commits May 20, 2026 01:41
Strangler-fig migration starts. New Vite + React 18 + TS strict app under
client-next/, mounted by Express at /v3 behind PGLENS_V3 flag while legacy
client/ stays default. Ports six screens against the existing API: landing,
sidebar (connections + schemas + tables search), table viewer (TanStack
Table + react-virtual + page/sort), schema viz (@xyflow/react with FK
edges), connection dialog (URL + params modes, create + edit), and query
runner (lazy Monaco editor, Cmd/Ctrl+Enter). Adds POST /api/query as the
advanced-mode escape hatch. Stack: shadcn/ui + Tailwind, TanStack Query +
Router, Zustand for active-connection state (persisted), Zod for all API
response validation.
Implements roadmap 3.3. Connection passwords move out of plaintext
~/.pglens/connections.json into the OS keychain via keytar; existing
records are migrated transparently on first boot and the file becomes
metadata-only. The server binds 127.0.0.1 (override with PGLENS_BIND)
and gates every route behind a per-install token stored at
~/.pglens/token; the CLI prints a token-bearing URL and the server sets
an HttpOnly cookie + 302s to a clean path on first visit. Replaces the
`[a-zA-Z0-9_]+` identifier regex with a proper double-quote escaper so
mixed-case and Unicode identifiers work. Standardizes error responses
to `{ error: { code, message, hint? } }` with a legacy `errorMessage`
mirror for the v2 client. All API routes pick up Zod request validation
(body / query / params). Adds pino daily-rotating JSON logs at
~/.pglens/logs/pglens.log.N plus `pglens logs`, `pglens token`, and
`pglens url` CLI commands. v3 client sends the cookie via
credentials:'same-origin' and parses the new envelope (with fallback to
the legacy string shape).
Implements roadmap §3.4. Adds three test tiers and a GitHub Actions
matrix. Backend uses node:test with 33 unit tests covering identifier
escaping, connection-URL parsing, error envelope, request validation,
and the token middleware — overall 87% line / 75% branch coverage,
well above the 60% bar set in the roadmap. Frontend uses Vitest +
jsdom + Testing Library with 11 unit tests covering the ApiError
envelope parser and the persisted Zustand store (75% coverage on
lib + store). Integration tests boot the real Express server against
a postgres:16 service container (docker-compose.test.yml locally,
GitHub services in CI) and exercise the full auth + connect + masked
URL + mixed-case identifier flow — env-gated via PGLENS_TEST_DB_URL
so they skip cleanly without docker. Playwright drives the v3 landing
through a real `pglens serve` to verify the token redirect and 401
envelope end-to-end. CI runs the unit suite on Node 18/20/22 across
ubuntu/macos/windows, with integration + e2e gated to ubuntu.
Refactors auth.js to export createTokenMiddleware(expected) so the
middleware is testable without touching the on-disk token file.
</parameter>
Closes Phase 0 §3.5 of the roadmap. The vanilla `client/` directory is
deleted and the React/TS app is now served at `/`; the legacy `/v3/*`
path 301-redirects to `/` so existing bookmarks still work, and the
package + CLI banner are bumped to 3.0.0. Reaches feature parity with
2.3.0 in the new stack: multi-tab workspace, theme switcher
(light/dark/system, persisted, OS-preference-aware), Cmd+K spotlight
search, per-connection Edit/Disconnect menu, schema PATCH on dropdown
change, landing page connections grid, streaming backup export with a
bottom-right progress toast (current table + bytes written + cancel),
themed scrollbars (color-scheme + WebKit pseudo-elements), and an
Asimovian wordmark font on the logo. Schema visualizer rewritten on
top of @dagrejs/dagre with LR/TB direction toggle, hover spotlight,
smoothstep edges + arrows, theme-synced MiniMap that highlights the
hovered table, and an export menu that ships SVG + Mermaid ER (copy
to clipboard or download .mmd). Edit Connection dialog now prefills
both URL and Parameters modes; the server treats a "***" password as
"keep the existing keychain entry" so name/SSL/schema can be saved
without retyping the password. Table viewer gets a top progress bar,
inline "updating…" spinner, and dimmed grid during refetch, and no
longer briefly renders the previous table's rows when switching
tables (placeholderData is now scoped by tableName). Misc UI fixes:
custom Select chevron centered against the input's full height,
per-page dropdown width + label tightened, MiniMap visible in both
themes with explicit background + border. CHANGELOG.md updated with
the full 3.0.0 entry under Added / Changed / Removed / Security.
Table reads ran 4 sequential round-trips per page (metadata, PK,
count, data), ~2.3s/page on remote DBs where each query costs a full
RTT. Cache column metadata per (connection, schema, table) with a 30s
TTL so pagination/sort skips the catalog introspection, derive the
primary key from cached columns (drops a query), and run COUNT and the
data fetch concurrently. Cache-hit page time drops to ~one RTT (~0.95s).

Invalidate metadata on /query (DDL), /import, and /disconnect so schema
changes don't serve stale columns past the TTL.
Add a Spinner/Loading component backed by unicode-spinner (subscribe
mode, braille variant) and use it for every loading indicator: table
rows, connections, tables, schema, editor, plus Run/Export/Connect
button pending states. Replaces the lucide Loader2 spinners. Generic
"Loading…" messages made specific (e.g. "Loading {table} rows…",
"Running query…", "Exporting backup…").
- TLS: sslMode `require` now verifies certs (rejectUnauthorized: true),
  closing a MITM gap; `prefer`/default stay lenient for self-signed dev DBs
- add loopback Host-header allowlist as DNS-rebinding defense
- fix protocol-relative open redirect in the /v3 handler
- sanitize export filename to block Content-Disposition header injection
- stop returning err.message on 500s (logged server-side, generic to client)
- run /query SET search_path + the user SQL on one reserved connection so
  the search_path can't land on a different pooled backend
- remove the unsupported /import route (unbounded body / memory DoS)
- npm audit fix: resolve path-to-regexp ReDoS + qs DoS (0 vulnerabilities)
cmd.exe does not expand the `test/unit/*.test.js` glob and node 18/20 do
not glob `--test` arguments, so Windows runners matched no files and
exited 1. Enumerate the test dir explicitly via scripts/run-tests.js.
The published package must ship the built React frontend that the server
serves from client-next/dist, and nothing else.

- Add package.json "files" allowlist (bin, src, client-next/dist, README)
  so npm stops shipping TS source, coverage, lockfiles, and tests.
- Add prepack to build client-next before packing so dist is fresh.
- Add client-next/.npmignore so npm ignores that dir's .gitignore (which
  excludes dist); the root files allowlist still restricts to dist.
- Delete .github/workflows/release.yml: it built electron .dmg/.exe via
  nonexistent dist:<platform> scripts; pglens is a CLI npm package.
@tsvillain tsvillain merged commit d7439ef into dev May 21, 2026
21 of 23 checks passed
@tsvillain tsvillain deleted the 3.0.0 branch May 21, 2026 20:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant