Skip to content

[DEV-1779] Fix event revision returned as a number instead of a bigint#520

Merged
w1am merged 3 commits into
masterfrom
refactor/bridge-0.2.1-event-types
Jun 23, 2026
Merged

[DEV-1779] Fix event revision returned as a number instead of a bigint#520
w1am merged 3 commits into
masterfrom
refactor/bridge-0.2.1-event-types

Conversation

@w1am

@w1am w1am commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

resolvedEvent.event.revision is now a bigint at runtime, matching its declared type. It was previously a number, so revision === 0n returned false and revision + 1n threw.

Closes #513

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Rely on @kurrent/bridge 0.2.1 for runtime event type materialization
✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

Description

• Upgrade @kurrent/bridge to 0.2.1 to receive final JS runtime event types.
• Remove redundant BigInt/Date coercion in Rust event conversion helpers.
• Add an integration test asserting bigint positions/revisions and Date created timestamps.
Diagram

graph TD
  A["readStream tests"] --> B["db-client readStream"] --> C["convertRustEvent/Record"] --> D["@kurrent/bridge 0.2.1"] --> E["EventStoreDB"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Keep coercion with runtime type-guard (backward compatible)
  • ➕ Allows consumers to downgrade/float @kurrent/bridge without breaking runtime assumptions
  • ➕ Provides a clearer error path if types unexpectedly regress
  • ➖ Adds branching and redundancy now that bridge guarantees final runtime types
  • ➖ Risk of double-coercion bugs (e.g., BigInt(BigInt)) if checks are incomplete
2. Centralize coercion in a single normalization layer
  • ➕ Single place to handle historical/edge-case conversions
  • ➕ Makes future bridge changes easier to adapt to
  • ➖ Extra abstraction/indirection for a now-simple pass-through mapping
  • ➖ Not needed if @kurrent/bridge is the contract for materialized types

Recommendation: Proceed with the PR’s approach: bump @kurrent/bridge and treat its returned runtime types as the source of truth. The added test provides a practical contract check, and removing redundant coercion reduces risk of double-conversion and improves clarity.

Files changed (4) +27 / -12

Refactor (1) +4 / -10
convertRustEvent.tsRemove redundant BigInt/Date coercion in Rust event conversion +4/-10

Remove redundant BigInt/Date coercion in Rust event conversion

• Stops re-coercing commitPosition, created, and position fields, passing through the values returned by @kurrent/bridge 0.2.1. This relies on bridge materializing runtime types (bigint and Date) directly.

packages/db-client/src/utils/convertRustEvent.ts

Tests (1) +21 / -0
readStream.test.tsAdd runtime type assertions for readStream events +21/-0

Add runtime type assertions for readStream events

• Adds an integration test ensuring revision/position are bigint and created is a Date when reading a single event from a stream. This guards the contract expected from @kurrent/bridge 0.2.1 and the conversion layer.

packages/test/src/streams/readStream.test.ts

Other (2) +2 / -2
package.jsonBump @kurrent/bridge to ^0.2.1 (benchmark package) +1/-1

Bump @kurrent/bridge to ^0.2.1 (benchmark package)

• Updates the benchmark package dependency on @kurrent/bridge from ^0.2.0 to ^0.2.1 to align runtime event typing behavior with the updated bridge.

packages/benchmark/package.json

package.jsonBump @kurrent/bridge to ^0.2.1 (db-client package) +1/-1

Bump @kurrent/bridge to ^0.2.1 (db-client package)

• Upgrades db-client to @kurrent/bridge ^0.2.1 so event fields arrive already materialized as bigint/Date/Buffer at runtime.

packages/db-client/package.json

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Ungated position type assertions 🐞 Bug ≡ Correctness
Description
readStream’s new "runtime types" test always expects event.position.commit/prepare to be
bigint, but position is only returned on server versions >= 22.6.0 so older servers will yield
undefined and fail the test. This will make the test suite flaky/failing depending on the server
version under test.
Code

packages/test/src/streams/readStream.test.ts[R107-108]

+        expect(typeof event.position?.commit).toBe("bigint");
+        expect(typeof event.position?.prepare).toBe("bigint");
Evidence
The public RecordedEvent contract documents that position is optional and only returned on server
versions later than 22.6.0, and this same test file already uses version gating for position-related
checks—so the new unconditional assertions will fail on unsupported versions.

packages/db-client/src/types/events.ts[128-133]
packages/test/src/streams/readStream.test.ts[299-321]
packages/test/src/streams/readStream.test.ts[92-110]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
A new test asserts `event.position.commit/prepare` are `bigint` unconditionally, but log `position` is not available on older server versions, causing failures when tests run against <22.6.0.

### Issue Context
This file already gates log-position-related assertions via `const supported = matchServerVersion`>=22.6.0`` and `optionalDescribe(supported)(...)` later in the suite.

### Fix Focus Areas
- packages/test/src/streams/readStream.test.ts[92-111]

### Suggested fix
Split the test assertions:
- Always assert `revision` is `bigint` and `created` is a `Date`.
- Wrap only the `position` type assertions in `optionalDescribe(matchServerVersion`>=22.6.0`)(...)`, or otherwise conditionally assert them based on `supported`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Position object always materialized 🐞 Bug ≡ Correctness
Description
convertRustRecord always returns a position object even when rustEvent.position is missing,
making event.position truthy while commit/prepare are undefined. This violates
RecordedEvent.position?: Position and can break consumers that treat if (event.position) as
“server supports log positions”.
Code

packages/db-client/src/utils/convertRustEvent.ts[R66-69]

  const position = {
-    commit:
-      rustEvent.position?.commit !== undefined
-        ? BigInt(rustEvent.position.commit)
-        : undefined,
-    prepare:
-      rustEvent.position?.prepare !== undefined
-        ? BigInt(rustEvent.position.prepare)
-        : undefined,
+    commit: rustEvent.position?.commit,
+    prepare: rustEvent.position?.prepare,
  };
Evidence
The type definitions require Position.commit/prepare to be bigint and document that
RecordedEvent.position is optional (only supported on newer servers). The converter currently
constructs and returns a position object regardless of whether the source had one, so callers can
observe a truthy position with undefined fields.

packages/db-client/src/types/index.ts[38-45]
packages/db-client/src/types/events.ts[128-133]
packages/db-client/src/utils/convertRustEvent.ts[55-105]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`convertRustRecord` builds `const position = { commit: rustEvent.position?.commit, prepare: rustEvent.position?.prepare }` and always includes it in the returned event. When the server doesn't provide a position, this yields `{commit: undefined, prepare: undefined}` which is truthy and violates the optional contract.

### Issue Context
- `RecordedEvent.position` is optional.
- `Position` requires `commit` and `prepare` to be `bigint`.

### Fix Focus Areas
- packages/db-client/src/utils/convertRustEvent.ts[55-105]

### Suggested fix
Set `position` to `undefined` when `rustEvent.position` is `undefined` and only create the object when present, e.g.:
```ts
const position = rustEvent.position
 ? { commit: rustEvent.position.commit, prepare: rustEvent.position.prepare }
 : undefined;
```
Then return `position` (which will be `undefined` when absent), so `if (event.position)` behaves correctly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +107 to +108
expect(typeof event.position?.commit).toBe("bigint");
expect(typeof event.position?.prepare).toBe("bigint");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Ungated position type assertions 🐞 Bug ≡ Correctness

readStream’s new "runtime types" test always expects event.position.commit/prepare to be
bigint, but position is only returned on server versions >= 22.6.0 so older servers will yield
undefined and fail the test. This will make the test suite flaky/failing depending on the server
version under test.
Agent Prompt
### Issue description
A new test asserts `event.position.commit/prepare` are `bigint` unconditionally, but log `position` is not available on older server versions, causing failures when tests run against <22.6.0.

### Issue Context
This file already gates log-position-related assertions via `const supported = matchServerVersion`>=22.6.0`` and `optionalDescribe(supported)(...)` later in the suite.

### Fix Focus Areas
- packages/test/src/streams/readStream.test.ts[92-111]

### Suggested fix
Split the test assertions:
- Always assert `revision` is `bigint` and `created` is a `Date`.
- Wrap only the `position` type assertions in `optionalDescribe(matchServerVersion`>=22.6.0`)(...)`, or otherwise conditionally assert them based on `supported`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@w1am w1am changed the title refactor: rely on @kurrent/bridge 0.2.1 to materialize event types fix: return event revision as a bigint at runtime Jun 22, 2026
@w1am w1am force-pushed the refactor/bridge-0.2.1-event-types branch from cab55ee to 951d0dd Compare June 22, 2026 10:20
@w1am w1am changed the title fix: return event revision as a bigint at runtime Fix event revision returned as a number instead of a bigint Jun 22, 2026
@w1am w1am force-pushed the refactor/bridge-0.2.1-event-types branch from 2ba46ed to 3b32a66 Compare June 22, 2026 12:00
@w1am w1am changed the title Fix event revision returned as a number instead of a bigint [DEV-1779] Fix event revision returned as a number instead of a bigint Jun 23, 2026
@linear-code

linear-code Bot commented Jun 23, 2026

Copy link
Copy Markdown

DEV-1779

@w1am w1am merged commit ee1c5be into master Jun 23, 2026
58 of 59 checks passed
@w1am w1am deleted the refactor/bridge-0.2.1-event-types branch June 23, 2026 08:40
w1am added a commit that referenced this pull request Jun 25, 2026
#520)

* Upgrade @kurrent/bridge to 0.2.2

* Simplify convertRustEvent to trust bridge-materialized types and honor optional position

* Add runtime-type tests and fix a no-op created assertion
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.

revision property in resolvedEvent.event is of type number but bigint is expected

1 participant