Conversation
…, tests, packaging) - Rewrite TS client around pg.Pool with feature parity to Go driver: connect, send, receive, ack, nack, subscribe, unsubscribe, newConsumer with handle/start. - Use JS bigint for msg_id, batch_id, and send() return — silent number-precision loss above 2^53 was a real correctness bug. Promote pg-types parser at module load time; documented as a side effect in README. - Add Consumer with AbortSignal-based cancellation, per-event-type dispatch, per-message nack on handler failure or unknown event type. - Error class hierarchy: PgqueError + Connection / QueueNotFound / ConsumerNotFound / Sql subclasses, mapped from raw pg errors. - Comprehensive vitest suite, env-gated via PGQUE_TEST_DSN: round-trip, default-type, validation, error mapping, payload edge cases, bigint preservation, subscribe idempotency, concurrent producers, nack routing to retry vs DLQ at the limit, custom retryAfter/reason, consumer dispatch + cancellation. - Publishable package: name 'pgque' (not 'pgque-ts-example'), version 0.2.0, Apache-2.0 LICENSE in module root, ESM exports map, engines >=20. - TSDoc on every exported symbol; strict + noUncheckedIndexedAccess. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
REV ReviewCI: Functional evidence: Verdict: FIXES NEEDED Blocking
Non-blocking
Potential
Anti-leak: ✅ clean. Zero hits for REV review (security, bugs, tests, guidelines, docs). SOC2 items skipped per project policy. |
Temporary bridge until PR #84 lands and replaces `client-smoke` CI step with `client-tests` (vitest). Exits 0 if PGQUE_TEST_DSN is unset; runs minimal send→tick→receive→ack otherwise. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents that importing pgque mutates the process-global pg-types parser (oid 20 → JS bigint) and what that means for other pg-using code in the same process. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clarifies that aborting the signal cuts the inter-poll sleep immediately but does not cancel an in-flight receive() call. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Default pool size 10 is intentional: the test asserts uniqueness and count only, no elapsed-time bounds, so 5-deep queueing is acceptable. Comment added inline to the test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents that undefined/circular refs cause JSON.stringify to throw or silently drop values, and that only plain JSON-compatible values are safe. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
payload is raw JSON text; consumer must call JSON.parse(). Added inline note and updated the handler example. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drop noisy npm ci-then-fallback pattern in favor of an explicit lockfile check, and add --passWithNoTests to vitest so the job stays green on branches that don't yet ship tests under clients/typescript/. Once PR #83 lands its vitest suite, the same command runs the new specs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
REV Review — PR #83 (round 2)CI: All green — Round 1 findings status:
Functional evidence: Read all six round-2 commits and the resulting tip-of-branch state of Verdict: READY FOR USER REVIEW (with one CI-signal note worth flagging for follow-up) BlockingNone. Non-blocking
Potential
Summary table
Anti-leakClean. REV-style review (security, bugs, tests, guidelines, docs). SOC2 items skipped per project policy. All round-1 findings addressed; surfacing one new CI-signal regression (smoke step is now a no-op) as MEDIUM non-blocking with a one-liner fix path. |
client-smoke ran only TestSmoke-named tests and didn't set PGQUE_TEST_DSN, so env-gated integration tests silently skipped. That's how the Nack placeholder bug shipped green in PR #79. New client-tests job: - Sets PGQUE_TEST_DSN pointing at the docker PG. - Runs full Go suite: go test -race -v ./... - Runs full Python suite: pytest -v clients/python/tests/ - Runs full TypeScript suite: npx vitest --run (replaces tsx src/smoke.ts). Switching the TS step to vitest also unblocks PR #83, which deletes the hardcoded src/smoke.ts in favor of the vitest suite. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop noisy npm ci-then-fallback pattern in favor of an explicit lockfile check, and add --passWithNoTests to vitest so the job stays green on branches that don't yet ship tests under clients/typescript/. Once PR #83 lands its vitest suite, the same command runs the new specs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
client-smoke ran only TestSmoke-named tests and didn't set PGQUE_TEST_DSN, so env-gated integration tests silently skipped. That's how the Nack placeholder bug shipped green in PR #79. New client-tests job: - Sets PGQUE_TEST_DSN pointing at the docker PG. - Runs full Go suite: go test -race -v ./... - Runs full Python suite: pytest -v clients/python/tests/ - Runs full TypeScript suite: npx vitest --run (replaces tsx src/smoke.ts). Switching the TS step to vitest also unblocks PR #83, which deletes the hardcoded src/smoke.ts in favor of the vitest suite. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop noisy npm ci-then-fallback pattern in favor of an explicit lockfile check, and add --passWithNoTests to vitest so the job stays green on branches that don't yet ship tests under clients/typescript/. Once PR #83 lands its vitest suite, the same command runs the new specs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
client-smoke ran only TestSmoke-named tests and didn't set PGQUE_TEST_DSN, so env-gated integration tests silently skipped. That's how the Nack placeholder bug shipped green in PR #79. New client-tests job: - Sets PGQUE_TEST_DSN pointing at the docker PG. - Runs full Go suite: go test -race -v ./... - Runs full Python suite: pytest -v clients/python/tests/ - Runs full TypeScript suite: npx vitest --run (replaces tsx src/smoke.ts). Switching the TS step to vitest also unblocks PR #83, which deletes the hardcoded src/smoke.ts in favor of the vitest suite. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop noisy npm ci-then-fallback pattern in favor of an explicit lockfile check, and add --passWithNoTests to vitest so the job stays green on branches that don't yet ship tests under clients/typescript/. Once PR #83 lands its vitest suite, the same command runs the new specs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
client-smoke ran only TestSmoke-named tests and didn't set PGQUE_TEST_DSN, so env-gated integration tests silently skipped. That's how the Nack placeholder bug shipped green in PR #79. New client-tests job: - Sets PGQUE_TEST_DSN pointing at the docker PG. - Runs full Go suite: go test -race -v ./... - Runs full Python suite: pytest -v clients/python/tests/ - Runs full TypeScript suite: npx vitest --run (replaces tsx src/smoke.ts). Switching the TS step to vitest also unblocks PR #83, which deletes the hardcoded src/smoke.ts in favor of the vitest suite. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop noisy npm ci-then-fallback pattern in favor of an explicit lockfile check, and add --passWithNoTests to vitest so the job stays green on branches that don't yet ship tests under clients/typescript/. Once PR #83 lands its vitest suite, the same command runs the new specs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrites
clients/typescript/from a small example into a publishable, feature-complete driver matching the Go client's API surface and behavior.Parity table (after this PR)
Connect(ctx, dsn)connect(dsn)int64voidbigint"default""message"NackOptionscontext.ContextAbortSignalWithPollIntervalConsumerOptions.pollIntervalbigintfor msg_id / batch_idint64number(precision loss)bigintPgqueError+ 4 subclassesBugs found & fixed in the prior driver
Message.msg_id/batch_id/retry_counttyped asnumber—pgreturns Postgresbigintas string by default; usingnumbersilently corrupts data aboveNumber.MAX_SAFE_INTEGER. Now JSbigint.send()returnedvoid, dropping the SQL function'sbigintevent id. Now returnsbigint.Nack, no high-levelConsumer— half the surface the Go driver exposes.package.jsonwasprivate: true/ namepgque-ts-example. Couldn't ship to npm. Nowpgque@0.2.0.LICENSEin module root (npm requires it; pkg.go.dev-equivalent). Added Apache-2.0."message"while SQLpgque.senddefaults to"default". Semantic drift. Fixed.Client(single connection) — no pool. Concurrent producers serialized + reconnect-fragile. Nowpg.Pool.src/smoke.ts. File deleted.Tests (env-gated via
PGQUE_TEST_DSN)test/client.test.ts,test/consumer.test.ts,test/nack.test.ts— 22 tests total. WithoutPGQUE_TEST_DSNonly the bad-DSN test runs (1 passes); others auto-skip cleanly. With a live DB the suite covers:"default"[]PgqueQueueNotFoundErrorsubscribeidempotency,unsubscriberemovesPromise.all(verifies pool)retry_queue, not DLQretryAfter/reasondead_letterAbortSignalstopsconsumer.start()promptly even with longpollIntervalHow to run locally
Verified in this branch
npm installcleannpm run checkpasses (bothtsconfig.jsonandtsconfig.test.json)npm run buildcleannpx vitest --run: 1 passed, 21 skipped (no DSN locally)Out of scope / deferred
npm publish) — release-time decision.Bug spotted in Go driver (not fixed here)
While auditing the Nack composite-type call shape, I count 12 placeholders in the Go SQL string
ROW(\$2..\$12)::pgque.messageagainst 11 supplied args — and thepgque.messagecomposite type itself has 10 fields, so evenROW(\$2..\$11)would be more correct. Either Go has a real bug here or I'm miscounting. Worth a manual eyeball atclients/go/pgque.go:97. The TS implementation in this PR uses 10 ROW elements +\$1/\$12/\$13for batch/retryAfter/reason and is verified against the SQL signature.Anti-leak
No mention of any private context anywhere in the diff or commit message.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com