Skip to content

✨ Support any handler type in context-api#196

Merged
taras merged 2 commits intomainfrom
context-api/support-any-handler-type
Mar 20, 2026
Merged

✨ Support any handler type in context-api#196
taras merged 2 commits intomainfrom
context-api/support-any-handler-type

Conversation

@taras
Copy link
Member

@taras taras commented Mar 18, 2026

Motivation

The @effectionx/context-api only supported API members that are Operation<T> or (...args) => Operation<T>. In effection v4-1-alpha, API members can be any kind of value — sync functions, Operation-returning functions, plain Operations, and plain constants. This PR brings context-api to parity with v4-1-alpha's API system.

Member kind Before After
*fn(): Operation<T>
Operation<T> (value)
() => T (sync function) ❌ Rejected by Handler type ✅ Lifted to () => Operation<T>
T (plain constant) ❌ Rejected by Handler type ✅ Lifted to Operation<T>

Approach

  • Removed Handler constraintcreateApi now accepts A extends {} instead of A extends Record<string, Handler>, matching v4-1-alpha
  • Updated Operations<A> type mapping — checks Operation<unknown> first (before function check) to prevent Operations from being misclassified, then handles sync functions by lifting (...args) => T to (...args) => Operation<T>, and constants by lifting T to Operation<T>
  • Updated Around<A> type — middleware mirrors the handler's raw type, so sync function middleware is sync and Operation middleware is Operation-returning
  • Added isOperation() runtime guard — with native iterable exclusion (strings, arrays, Maps, Sets) to prevent them from being mistaken for Operations when deciding whether to yield* a result
  • Updated runtime operation creation — uses isOperation() to decide at runtime whether to yield* the result or return it directly
  • Added 8 new tests — sync functions, constants, sync middleware, mixed handler types, native iterable safety, scope isolation for sync middleware
  • Bumped version to 0.5.0 (minor, new capability)

Note: invoke (calling API members from a Scope directly) is deferred to a follow-up.

Summary by CodeRabbit

  • Breaking Changes

    • Middleware ordering semantics updated: "min" priority and innermost scope middleware now take precedence.
    • Public API type constraints relaxed and several API signatures adjusted (may require consumer updates).
    • Package version bumped.
  • Bug Fixes

    • Native iterables (arrays, strings, Map, Set) are no longer misidentified as operations.
  • Tests

    • Large suite of new tests covering sync vs generator handlers, middleware interactions, scope isolation, and edge cases.

Bring context-api to parity with effection v4-1-alpha's API system by
allowing API members to be any kind of value — not just Operations.

- Sync functions are lifted to Operation-returning functions
- Plain constants are lifted to Operations
- Middleware type matches the handler's raw signature (sync stays sync)
- Added isOperation() runtime guard with native iterable exclusion
- Operation check comes before function check in type mapping to prevent
  misclassification of Operation implementations
@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

📝 Walkthrough

Walkthrough

Refactors context-api types and runtime to treat functions/constants as Operations when needed, changes middleware insertion order for min, adds runtime helpers to detect Operations/native iterables, expands tests extensively for sync/generator/constant handlers and scope/middleware interactions, and bumps package version to 0.5.1.

Changes

Cohort / File(s) Summary
Tests
context-api/context-api.test.ts
Expanded test coverage (+186/-2) validating sync/generator/constant handler invocation, argument passing, middleware (around) on mixed handler types, scope isolation, and updated min/max middleware ordering expectations.
Core Types & Runtime
context-api/mod.ts
Reworked Operations<A> and Around<A> typings (map over keyof A, avoid treating Operation as callable, lift sync returns/constants into Operations). Removed Handler constraint; createApi now A extends {}. Runtime: dual-value iteration for handlers, isOperation and isNativeIterable helpers, and changed min middleware prepending behavior.
Package Metadata
context-api/package.json
Package version bumped from 0.4.0 to 0.5.1.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Caller as Caller
participant API as createApi
participant Middleware as MiddlewareRegistry
participant Handler as FieldHandler
participant Operation as Operation/Value
Caller->>API: invoke operation
API->>Middleware: apply middleware chain (min/max ordering)
Middleware->>Handler: call handler (may be sync/gen/constant)
Handler-->>Operation: returns Operation or direct value
Middleware->>Operation: intercept / yield / pass-through
Operation-->>Caller: final result

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • cowboyd
🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Support any handler type in context-api' directly and clearly summarizes the main change: expanding handler type support to include sync functions and constants.
Description check ✅ Passed The description includes both required template sections (Motivation and Approach) with comprehensive detail on the problem, solution, and changes made.
Policy Compliance ✅ Passed Pull request complies with all Strict and Recommended policies including Package.json Metadata and Version Bump requirements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch context-api/support-any-handler-type
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 18, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@effectionx/context-api@196

commit: b635a81

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@context-api/mod.ts`:
- Around line 152-164: The isOperation type guard misidentifies TypedArray
instances (e.g., Uint8Array, Int32Array) as Operations because they implement
[Symbol.iterator]; update the guard to exclude them by adding a TypedArray
check—either extend isNativeIterable to return true for TypedArray instances or
add a dedicated helper like isTypedArray(target) using
ArrayBuffer.isView(target) && !(target instanceof DataView) (or explicit
instanceof checks for Uint8Array/Int8Array/etc.), and use that in the
isOperation return condition alongside the existing !isNativeIterable and
Symbol.iterator checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d6c9e03e-989a-49e5-9caa-36486035fb04

📥 Commits

Reviewing files that changed from the base of the PR and between a495cb4 and aa8bb10.

📒 Files selected for processing (3)
  • context-api/context-api.test.ts
  • context-api/mod.ts
  • context-api/package.json

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
context-api/mod.ts (1)

158-172: ⚠️ Potential issue | 🟠 Major

isOperation() still misclassifies iterable constants.

The guard only excludes strings, arrays, Maps, and Sets. Uint8Array/other ArrayBuffer views—and any domain object with [Symbol.iterator]—still take the Operation path and get yield*ed instead of returned, so the new constant/sync handler support is still incorrect for those values. At minimum, harden isNativeIterable() against typed arrays here; supporting arbitrary iterables as plain values will need a stronger runtime brand than [Symbol.iterator].

💡 Minimum hardening
 function isNativeIterable(target: unknown): boolean {
   return (
     typeof target === "string" ||
     Array.isArray(target) ||
     target instanceof Map ||
-    target instanceof Set
+    target instanceof Set ||
+    ArrayBuffer.isView(target)
   );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@context-api/mod.ts` around lines 158 - 172, The type-guard misclassifies
typed-array/ArrayBuffer view values as Operations; update isNativeIterable()
(used by isOperation()) to treat ArrayBuffer views as native iterables by
returning true when ArrayBuffer.isView(target) (and also handle DataView if
needed), so typed arrays (e.g., Uint8Array) are excluded from the Operation path
and will be returned as constants rather than being yield*-ed; do not try to
treat arbitrary custom iterables as native here (that requires a stronger
runtime brand).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@context-api/mod.ts`:
- Around line 62-63: The generic constraint on createApi is too broad (A extends
{}) and allows non-string keys while Object.keys(handler) only captures
string-keyed properties; update the generic to A extends Record<string, unknown>
so the type matches runtime behavior (affecting createApi, fields,
Object.keys(handler) and the returned Api<A>) and ensure operations/around and
other consumers only see string-keyed members.
- Around line 13-15: The public handler generic A currently allows PromiseLike
values and functions that return PromiseLike, which bypasses your
structured-concurrency guarantees; update the handler type A to exclude
PromiseLike members (e.g. constrain A with a utility like
NonPromiseLikeKeys/ExcludePromiseLike or require A extends Record<string,
unknown> & { [K in keyof A]: A[K] extends PromiseLike<any> ? never : A[K] }) and
also exclude functions whose ReturnType is PromiseLike. In addition, in the
handler-to-middleware lifting logic and at the isOperation() branches (the
checks referenced by isOperation and the code paths around lines ~37–44, ~91 and
~102), bridge any raw Promise/PromiseLike into an Operation (using your
Operation factory/constructor or an explicit wrapper) before returning so that
Promises are yielded as scope-owned Operations rather than returned directly.
Ensure Middleware and Operation type mappings (the mapped type using
Middleware<TArgs,TReturn>) use Awaited/Unwrap to work with non-Promise returns
after the constraint is applied.

---

Duplicate comments:
In `@context-api/mod.ts`:
- Around line 158-172: The type-guard misclassifies typed-array/ArrayBuffer view
values as Operations; update isNativeIterable() (used by isOperation()) to treat
ArrayBuffer views as native iterables by returning true when
ArrayBuffer.isView(target) (and also handle DataView if needed), so typed arrays
(e.g., Uint8Array) are excluded from the Operation path and will be returned as
constants rather than being yield*-ed; do not try to treat arbitrary custom
iterables as native here (that requires a stronger runtime brand).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9957aa2a-ef87-4a43-913a-c0d8e873a26d

📥 Commits

Reviewing files that changed from the base of the PR and between aa8bb10 and b635a81.

📒 Files selected for processing (3)
  • context-api/context-api.test.ts
  • context-api/mod.ts
  • context-api/package.json

@taras taras merged commit 60ea3a3 into main Mar 20, 2026
7 checks passed
@taras taras deleted the context-api/support-any-handler-type branch March 20, 2026 19:04
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