Skip to content

v6.1 pre-release polish#20

Merged
meritt merged 5 commits intomainfrom
feature/release-polish
Apr 27, 2026
Merged

v6.1 pre-release polish#20
meritt merged 5 commits intomainfrom
feature/release-polish

Conversation

@meritt
Copy link
Copy Markdown
Owner

@meritt meritt commented Apr 27, 2026

Summary

Pre-release fixes for v6.1.0 based on a multi-angle audit of the v6.0.0 → main delta.

  • close() and emit() reliability: serialize concurrent close() through _closing so the second call awaits the actual native teardown; throw a clean client closed during open instead of an internal TypeError when open() races close(); wrap default console.error in try/catch so a hostile or broken console (test mocks, EPIPE, APM wrappers) cannot break the fail-silent contract.
  • each() shared-cursor closure fixed via a factory model: [Symbol.asyncIterator]() opens its own native cursor, while Symbol.asyncDispose still closes everything in scope through a Set tracked on the outer closure. Two parallel for await loops on the same each(...) value now each see the full result set instead of one trampling the other into a Cannot use a session that has ended emit.
  • count({}) speedup: short-circuits to estimatedDocumentCount, ~20× faster on large collections. Notes the estimated path may drift on sharded collections with orphans / after unclean shutdown.
  • save() defensive guard: replace path uses ?? 0 for upsertedCount / modifiedCount / matchedCount to defend against a partial driver response producing NaN > 0 = false.
  • README documents the v6.1 surface (each, indexes, positional updates, AbortSignal, asyncDispose) and the empty-filter-vs-aborted-signal corner case.

Test plan

  • `pnpm lint` clean
  • `pnpm format:check` clean
  • `pnpm test` — 174/174 (was 166/166; +8 regression tests across each.js, observability.js, client.js, index.js)
  • `pnpm coverage` — `lib/client.js` 97.96% lines / 93.02% branches; `lib/collection.js` 99.37% / 94.31%; `prepare.js` / `utils.js` / `index.js` 100%
  • `pnpm pack --dry-run` — ships only `lib/`, `LICENSE`, `package.json`, `readme.md`

meritt added 4 commits April 28, 2026 00:08
- close(): serialize concurrent calls through a shared `_closing`
  promise so the second call awaits the actual native teardown
  instead of returning ahead of it.
- open(): after `await this._connecting`, throw a clean
  "client closed during open" if `close()` nulled `db` mid-flight,
  replacing the noisy TypeError surfaced through outer catch.
- emit(): wrap the default `console.error` call in try/catch so a
  hostile or broken console (test mocks, EPIPE, APM wrappers)
  cannot break the fail-silent contract.

Tests: client.js gains race + concurrent-close cases;
observability.js gains a survey that exercises every public
method against a throwing console.error.
- each(): make `[Symbol.asyncIterator]()` open its own native cursor
  via a per-iteration local; track all open cursors in a Set on the
  outer closure so `Symbol.asyncDispose` still closes everything in
  scope. Two parallel `for await` loops on the same `each(...)` value
  now each see the full result set instead of one trampling the
  other into a `Cannot use a session that has ended` emit.
- count({}): short-circuit to `estimatedDocumentCount`, ~20x faster
  on large collections. JSDoc notes the estimated path may drift on
  sharded collections with orphans or after unclean shutdown.
- save(): replace path now uses `?? 0` for upsertedCount /
  modifiedCount / matchedCount to defend against a partial driver
  response producing NaN > 0 = false.

Tests: each.js gains parallel + sequential reuse cases; index.js
pins the estimatedDocumentCount short-circuit with a mock survey.
Adds Streaming reads, Indexes, Positional updates, AbortSignal
sections; Symbol.asyncDispose example next to close(); refreshes
the Collection methods table with each / createIndex /
ensureIndexes / signal columns.

Notes the count({}) → estimatedDocumentCount short-circuit and
the empty-filter-vs-aborted-signal corner case explicitly.
@meritt meritt self-assigned this Apr 27, 2026
@coveralls
Copy link
Copy Markdown

coveralls commented Apr 27, 2026

Coverage Status

coverage: 98.972% (-0.6%) from 99.563% — feature/release-polish into main

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1de0a9f3b5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/client.js Outdated
The simple `if (this._closing) return this._closing` early-return
dropped legitimate close requests that arrive after a reopen.
Sequence: close() #1 starts (resets state, awaits native teardown)
→ another operation triggers open(), which installs a fresh native
client on `this.client` → close() #2 hits the early-return, awaits
the first close, and exits without closing the newly opened client.

Fix: each close() now creates its own task that (a) awaits the
previous in-flight close, (b) snapshots `this.client` and bails
if another close already nulled it, (c) otherwise resets state and
calls native close. Concurrent closes without reopen still share
one native close (the second snapshot sees null and bails). Closes
that race a reopen each close their own client.

Adds a regression test that primes a connection, starts close() #1,
forces a reopen via collection.count() (which sync-installs a new
native client), then close() #2 — both client A and client B must
close exactly once.
@meritt meritt merged commit 5a9bc7a into main Apr 27, 2026
6 checks passed
@meritt meritt deleted the feature/release-polish branch April 27, 2026 21:24
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.

2 participants