✨ feat(context-api): user-defined middleware groups#215
Conversation
createApi now accepts an ordered list of middleware groups via
options.groups. Each group declares a name and a mode of "append"
(earlier registrations outer, parent-outer/child-inner across scopes)
or "prepend" (later registrations outer, child-outer/parent-inner).
around({ at }) targets a declared group and defaults to the first one.
The default configuration remains
[{ name: "max", mode: "append" }, { name: "min", mode: "prepend" }],
so existing callers keep their current behavior, including the
default-to-max semantics.
This lets consumers like Tisyn express structural lanes (e.g. a
"replay" lane between wrappers and defaults) as an invariant of the
API rather than by coordinating install order.
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 39 minutes and 2 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe changes generalize the middleware architecture from fixed "max"/"min" lanes to a configurable system of named middleware groups. The Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 5 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
commit: |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
context-api/README.md (1)
7-11: 🧹 Nitpick | 🔵 TrivialMinor: update intro to reflect arbitrary groups.
The opening still says "supports min/max priority ordering". With this PR, users can declare arbitrary ordered groups; consider rephrasing so the entry-point description advertises the full capability (while still mentioning min/max as the default).
✏️ Proposed tweak
-Often called "Algebraic Effects" or "Contextual Effects", Context APIs let you -access an operation via the context in a way that it can be easily (and -contextually) wrapped with middleware. Middleware is powered by -[`@effectionx/middleware`](../middleware/README.md) and supports min/max priority -ordering. +Often called "Algebraic Effects" or "Contextual Effects", Context APIs let you +access an operation via the context in a way that it can be easily (and +contextually) wrapped with middleware. Middleware is powered by +[`@effectionx/middleware`](../middleware/README.md) and supports ordered +middleware groups — with `min`/`max` as the default two-lane configuration.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@context-api/README.md` around lines 7 - 11, Update the README intro sentence that currently says middleware "supports min/max priority ordering" to instead advertise that middleware supports arbitrary ordered groups with min/max as the default; specifically edit the sentence referencing `@effectionx/middleware` to mention "supports arbitrary ordered middleware groups (min/max priority ordering is the default)" so the entry-point description reflects the new capability while retaining the existing min/max wording.
🤖 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 29-57: The CreateApiOptions.groups JSDoc should mention callers
can pass a readonly tuple (e.g. groups: [...] as const) to preserve
literal-union inference for Group; update the comment above the CreateApiOptions
type to add a short sentence advising to use the "as const" pattern when passing
groups so the MiddlewareGroup<Group>[] (and MiddlewareGroup) retain literal
types for Group during inference.
In `@context-api/scope-middleware.test.ts`:
- Around line 1545-1613: The test's duplicate-group assertion is too loose
because the top-level API name "groups.dup" can satisfy /max/; update the
assertion in the "createApi throws on duplicate group names" test so it verifies
that the error message contains the duplicate-group phrase adjacent to the
duplicated name (e.g. change the second expect on the caught message to match
/duplicate group name.*\bmax\b/ or otherwise assert that the "duplicate group
name" substring and the symbol "max" both appear in the same message context),
locating the change around the test that calls createApi(...) and inspects
message from the thrown Error captured in that spec.
---
Outside diff comments:
In `@context-api/README.md`:
- Around line 7-11: Update the README intro sentence that currently says
middleware "supports min/max priority ordering" to instead advertise that
middleware supports arbitrary ordered groups with min/max as the default;
specifically edit the sentence referencing `@effectionx/middleware` to mention
"supports arbitrary ordered middleware groups (min/max priority ordering is the
default)" so the entry-point description reflects the new capability while
retaining the existing min/max wording.
🪄 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: bd0d8330-aabc-44e8-896a-92a405bcd4f7
📒 Files selected for processing (3)
context-api/README.mdcontext-api/mod.tscontext-api/scope-middleware.test.ts
Tighten around() so options?: { at: Group } — options is still optional,
but if you pass it, at is required. Prevents custom-group callers from
silently landing in the first lane by omission.
- bump context-api to 0.7.0 for the new published API - reframe README intro around ordered middleware groups - document the `as const` idiom on CreateApiOptions JSDoc - tighten duplicate-group-name test to anchor on the duplicate list
|
Addressed the remaining CodeRabbit feedback in |
Motivation
Consumers of
@effectionx/context-api(notably Tisyn) need a third structural middleware lane that sits between general wrappers and core-providing middleware — specifically, areplaylane positioned asmax wrappers → replay restore → dispatch/default min → core.Today
context-apihard-codes exactly two lanes (maxandmin), so replay restore has to compete with otherminmiddleware by install order. That encodes a fragile invariant in call ordering instead of in the API surface. The fix is to let eachcreateApi()declare the lanes it needs, keepingmax/minas the backward-compatible default.Approach
options.groupsoncreateApi(): an ordered list of{ name, mode }wheremodeis"append"(earlier registrations outer; parent-outer/child-inner across scopes) or"prepend"(later registrations outer; child-outer/parent-inner).around({ at })now targets any declared group name;atdefaults to the first declared group.[{ name: "max", mode: "append" }, { name: "min", mode: "prepend" }], so existing call sites — including the "defaults to max" semantics — are unchanged.createApi()call time: throws on emptygroupsand on duplicate names;around()throws at runtime on an unknownat, with the known group names in the message.GroupMode,MiddlewareGroup<Name>,CreateApiOptions<Group>.Api<A, Group>gains a second generic with a default of"max" | "min"so existingApi<A>usages keep compiling. Callers passgroups: [...] as constto infer the literal union.describe("custom groups", ...)block inscope-middleware.test.tscovering declared order, install-order semantics per mode, middle-lane stability, parent/child composition across all lanes, isolation after scope exit, live updates for spawned tasks on the middle lane, mixed later-parent updates, and all three validation paths. Existing tests unchanged.createApiandaroundAPI reference entries.Verification (all green):
pnpm check,pnpm lint,pnpm fmt:check, andpnpm test(389 passing, 6 skipped — 11 new tests). No runtime behavior change for existingmax/mincallers.