Skip to content

[DEV-1654] Support V2 projection engine on createProjection#502

Merged
w1am merged 3 commits intomasterfrom
feat/projection-engine-v2
May 6, 2026
Merged

[DEV-1654] Support V2 projection engine on createProjection#502
w1am merged 3 commits intomasterfrom
feat/projection-engine-v2

Conversation

@w1am
Copy link
Copy Markdown
Collaborator

@w1am w1am commented May 5, 2026

Summary

Adds a new engineVersion option to createProjection so callers can opt into the V2 projection engine. V1 remains the default and the existing call shape is unchanged for V1 callers.

Usage

import { PROJECTION_ENGINE_V2 } from "@kurrent/kurrentdb-client";

await client.createProjection(name, query, {
  engineVersion: PROJECTION_ENGINE_V2,
});

The accepted values are PROJECTION_ENGINE_V1 ("v1") and PROJECTION_ENGINE_V2 ("v2"), exposed as the ProjectionEngineVersion union type.

Notes

  • The engine version is pinned at create time and cannot be changed later.
  • V2 does not support trackEmittedStreams, bi-state projections, or live outputState result streams. See the KurrentDB docs for the full list of V2 limitations before opting in.
  • V1 callers see no behavior change. The client only sends the engine_version field (gRPC) or engineversion query parameter (HTTP fallback) when V2 is explicitly selected, so legacy servers continue to receive the same request shape as before.

Refs DEV-1654.

Adds ProjectionEngineVersion enum and engineVersion option to
createProjection, plumbed through both gRPC (CreateReq.Options.engine_version)
and the HTTP fallback (engineversion query param).
@linear
Copy link
Copy Markdown

linear Bot commented May 5, 2026

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Support V2 projection engine selection in createProjection

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Adds ProjectionEngineVersion enum with V1 and V2 options
• Introduces engineVersion parameter to createProjection method
• Plumbs engine version through gRPC and HTTP protocols
• Adds test coverage for V2 projection engine creation
Diagram
flowchart LR
  A["ProjectionEngineVersion enum<br/>V1 default, V2 opt-in"] -->|"engineVersion option"| B["CreateProjectionOptions"]
  B -->|"gRPC path"| C["CreateReq.Options<br/>engine_version field"]
  B -->|"HTTP path"| D["Query param<br/>engineversion"]
  C --> E["Projection created<br/>with selected engine"]
  D --> E
Loading

Grey Divider

File Changes

1. packages/db-client/src/projections/createProjection.ts ✨ Enhancement +28/-0

Add engine version selection to createProjection

• Adds ProjectionEngineVersion enum with V1 (default) and V2 options
• Adds engineVersion parameter to CreateProjectionOptions interface
• Updates both gRPC and HTTP implementations to pass engine version
• Sets V1 as default when engine version not specified

packages/db-client/src/projections/createProjection.ts


2. packages/db-client/generated/kurrentdb/protocols/v1/projectionmanagement_pb.js Dependencies +31/-1

Generated protobuf code for engine_version field

• Adds engineVersion field to CreateReq.Options serialization
• Implements getter/setter methods for engine version
• Adds deserialization support for engine_version field (case 5)
• Adds binary serialization for engine_version as int32

packages/db-client/generated/kurrentdb/protocols/v1/projectionmanagement_pb.js


3. packages/db-client/generated/kurrentdb/protocols/v1/projectionmanagement_pb.d.ts Dependencies +3/-0

TypeScript type definitions for engine_version

• Adds TypeScript type definitions for getEngineVersion() and setEngineVersion() methods
• Updates AsObject type to include engineVersion: number field

packages/db-client/generated/kurrentdb/protocols/v1/projectionmanagement_pb.d.ts


View more (2)
4. packages/db-client/protos/kurrentdb/protocols/v1/projectionmanagement.proto ⚙️ Configuration changes +1/-0

Add engine_version field to proto definition

• Adds int32 engine_version = 5 field to CreateReq.Options message
• Documents field semantics: 0 or 1 = v1 (default), 2 = v2

packages/db-client/protos/kurrentdb/protocols/v1/projectionmanagement.proto


5. packages/test/src/projections/createProjection.test.ts 🧪 Tests +20/-0

Add test for V2 projection engine creation

• Imports ProjectionEngineVersion enum
• Adds test case for V2 engine projection creation
• Verifies V2 projection can be created successfully

packages/test/src/projections/createProjection.test.ts


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 5, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Unconditional HTTP engineversion param ✓ Resolved 🐞 Bug ☼ Reliability
Description
createProjectionHTTP always sends the new engineversion query parameter, even when the caller uses
the default V1 engine. This changes the request shape of the HTTP fallback path used when gRPC
track_emitted_streams isn’t supported, risking backward compatibility with older servers on that
path.
Code

packages/db-client/src/projections/createProjection.ts[146]

+        engineversion: engineVersion.toString(),
Evidence
The client explicitly routes to the HTTP implementation when track_emitted_streams isn’t supported
over gRPC, indicating this path targets older servers. The HTTP implementation now unconditionally
includes a brand-new query parameter (engineversion), so older servers that don’t recognize it may
reject the request.

packages/db-client/src/projections/createProjection.ts[64-83]
packages/db-client/src/projections/createProjection.ts[126-150]

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

### Issue description
`createProjectionHTTP` always includes `engineversion` in `searchParams`, even when using the default V1 engine. This can break backward compatibility for the HTTP fallback path used on servers that do not support `track_emitted_streams` over gRPC.

### Issue Context
The code intentionally falls back to HTTP for older servers. Adding a new, unconditional query parameter changes the legacy HTTP API call shape.

### Fix Focus Areas
- packages/db-client/src/projections/createProjection.ts[64-83]
- packages/db-client/src/projections/createProjection.ts[126-150]

### Suggested change
- Only include `engineversion` in HTTP `searchParams` when the caller explicitly opts into V2 (e.g., `engineVersion === ProjectionEngineVersion.V2`).
- Optionally also avoid calling `options.setEngineVersion(...)` on gRPC when using V1, so V1 remains “not set” rather than “explicitly set to 1”.

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



Remediation recommended

2. V2 allows trackEmittedStreams 🐞 Bug ≡ Correctness
Description
The ProjectionEngineVersion.V2 documentation states V2 does not support trackEmittedStreams, but
createProjection allows that combination and forwards both flags to the server. This permits callers
to construct a request the client itself documents as unsupported.
Code

packages/db-client/src/projections/createProjection.ts[R104-107]

  options.setContinuous(continuous);
  options.setQuery(query);
+  options.setEngineVersion(engineVersion);
Evidence
The enum documentation explicitly declares trackEmittedStreams unsupported for V2. The request
builder still sets continuous.track_emitted_streams from the option and also sets
engine_version, with no guard preventing the incompatible combination.

packages/db-client/src/projections/createProjection.ts[11-27]
packages/db-client/src/projections/createProjection.ts[86-108]

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

### Issue description
The API docs say V2 projections do not support `trackEmittedStreams`, but the client currently allows `engineVersion: V2` + `trackEmittedStreams: true` and sends it to the server.

### Issue Context
This is a client-side validation gap: the library is aware of the incompatibility (it’s documented) but doesn’t enforce it.

### Fix Focus Areas
- packages/db-client/src/projections/createProjection.ts[11-27]
- packages/db-client/src/projections/createProjection.ts[64-83]
- packages/db-client/src/projections/createProjection.ts[86-108]

### Suggested change
- Add a runtime guard early (e.g., in `Client.prototype.createProjection` or inside both transport implementations):
 - If `engineVersion === ProjectionEngineVersion.V2 && trackEmittedStreams === true`, throw a clear error (e.g., `InvalidArgumentError`) explaining the combination is not supported.

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


3. No V2 capability gating ✓ Resolved 🐞 Bug ≡ Correctness
Description
createProjection forwards engineVersion into the gRPC request without checking whether the
connected server advertises support for engine version selection. This makes it possible to request
V2 against servers that don’t support it, despite the client already using ServerFeatures-based
gating for other projection options.
Code

packages/db-client/src/projections/createProjection.ts[R93-96]

+    engineVersion = ProjectionEngineVersion.V1,
    ...baseOptions
  }: CreateProjectionOptions = {}
): Promise<void> {
Evidence
The repo has a ServerFeatures mechanism for per-method feature gating, and createProjection already
uses it to detect support for track_emitted_streams to decide transport. The new engine_version
field is added to the proto and is always set from user input, but no analogous support check exists
for the new capability.

packages/db-client/src/Client/ServerFeatures.ts[19-78]
packages/db-client/src/projections/createProjection.ts[64-83]
packages/db-client/src/projections/createProjection.ts[86-108]
packages/db-client/protos/kurrentdb/protocols/v1/projectionmanagement.proto[21-32]

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

### Issue description
`engineVersion` is sent to the server without validating that the server supports selecting an engine version for `ProjectionsService.create`. This can lead to V2 being requested on unsupported servers.

### Issue Context
The codebase already has a ServerFeatures-driven gating mechanism (used in createProjection for `track_emitted_streams`). The new `engine_version` field introduces another server capability dimension that should be validated similarly.

### Fix Focus Areas
- packages/db-client/src/projections/createProjection.ts[64-83]
- packages/db-client/src/projections/createProjection.ts[86-108]
- packages/db-client/src/Client/ServerFeatures.ts[19-78]
- packages/db-client/protos/kurrentdb/protocols/v1/projectionmanagement.proto[21-32]

### Suggested change
- If `engineVersion === ProjectionEngineVersion.V2`, check server capabilities before sending.
 - Prefer using `(await this.supports(ProjectionsService.create, <engine-version-feature-name>))`.
 - If not supported, throw a clear error (e.g., `UnsupportedError` or `InvalidArgumentError`) indicating engine version selection requires a newer server.

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


Grey Divider

Qodo Logo

Comment thread packages/db-client/src/projections/createProjection.ts Outdated
Switch the public enum to string values (V1="v1", V2="v2") and map to
the int32 wire format at the gRPC/HTTP boundary. Resolve option
defaults once at the entry instead of duplicating them in each helper.
@w1am w1am changed the title feat: support V2 projection engine on createProjection [DEV-1664] Support V2 projection engine on createProjection May 6, 2026
@w1am w1am changed the title [DEV-1664] Support V2 projection engine on createProjection [DEV-1654] Support V2 projection engine on createProjection May 6, 2026
@w1am w1am force-pushed the feat/projection-engine-v2 branch from 879611a to 89bbff7 Compare May 6, 2026 07:57
Replace the local TypeScript enum with constants in src/constants.ts
(PROJECTION_ENGINE_V1 / PROJECTION_ENGINE_V2) plus a union type in
src/types, matching the pattern used by NodePreference, ConsumerStrategy,
and other public string-valued enums.
@w1am w1am force-pushed the feat/projection-engine-v2 branch from 89bbff7 to 8bde488 Compare May 6, 2026 08:02
@w1am w1am self-assigned this May 6, 2026
@w1am w1am merged commit 81bfb39 into master May 6, 2026
30 checks passed
@w1am w1am deleted the feat/projection-engine-v2 branch May 6, 2026 08:16
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

@w1am 👉 Created pull request targeting release/v1.2: #504

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant