Skip to content

feat(dei): enforce JWT expiry & revocation; add kickIfInvalid; tests#939

Closed
Rhayxz wants to merge 1 commit intomiddleapi:mainfrom
Rhayxz:fix-durable-iterator-jwt-check
Closed

feat(dei): enforce JWT expiry & revocation; add kickIfInvalid; tests#939
Rhayxz wants to merge 1 commit intomiddleapi:mainfrom
Rhayxz:fix-durable-iterator-jwt-check

Conversation

@Rhayxz
Copy link
Copy Markdown

@Rhayxz Rhayxz commented Aug 27, 2025

Ensures JWT is checked on send and on inbound RPC. Adds optional revocation hook, closes WS with 4001/4003, updates router to guard .call via kickIfInvalid, and adds expiry tests.

Summary by CodeRabbit

  • New Features
    • Automatically detects and disconnects expired or revoked WebSocket sessions with dedicated close codes.
    • Adds a configurable hook to decide when a WebSocket should be disconnected.
    • Skips sending events to invalid sessions while continuing delivery to valid clients.
  • Bug Fixes
    • Prevents events from being sent to expired sessions.
  • Refactor
    • Converted call routing and event delivery to async for improved reliability.
  • Tests
    • Expanded coverage for token expiry scenarios with time-based assertions and async flows.

@vercel
Copy link
Copy Markdown

vercel Bot commented Aug 27, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
orpc Ready Ready Preview Comment Aug 27, 2025 7:28pm

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Aug 27, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 27, 2025

Walkthrough

The call handler in the durable event iterator is made async with an early token validation step. The WebSocket manager adds kickIfInvalid logic, close codes, an optional shouldKickWs hook, and makes publishEvent/sendEventsAfter async. Tests are updated for dynamic token timing, async behavior, and new expiry scenarios.

Changes

Cohort / File(s) Summary
Handler flow (async + early auth)
packages/durable-event-iterator/src/durable-object/handler.ts
Makes base.call.handler async; awaits websocketManager.kickIfInvalid(currentWebsocket) and throws UNAUTHORIZED if invalid before proceeding with method resolution and invocation.
WebSocket manager: validation & async send
packages/durable-event-iterator/src/durable-object/websocket-manager.ts
Adds kickIfInvalid, close codes 4001/4003, optional shouldKickWs hook. Changes publishEvent and sendEventsAfter to async, calling kickIfInvalid before sending.
Tests: handler timing update
packages/durable-event-iterator/src/durable-object/handler.test.ts
Replaces hard-coded timestamp with Date.now(); adjusts expectations for dynamic iat/exp.
Tests: websocket manager expiry + async
packages/durable-event-iterator/src/durable-object/websocket-manager.test.ts
Mocks hibernation; introduces dynamic token times; converts to async awaits; adds expiry tests validating close with 4001 and no sends; ensures valid sockets receive events.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant DO as Durable Object Handler
  participant WM as WebSocket Manager
  Client->>DO: RPC call via WebSocket
  DO->>WM: kickIfInvalid(ws)
  alt Token invalid
    WM-->>DO: true
    DO-->>Client: ORPCError(UNAUTHORIZED)
  else Token valid
    WM-->>DO: false
    DO->>DO: Resolve allowed methods from token
    DO->>Service: Invoke requested method
    Service-->>DO: Result/Stream
    DO-->>Client: Response/Events
  end
Loading
sequenceDiagram
  autonumber
  participant Publisher as Event Publisher
  participant WM as WebSocket Manager
  participant WS* as Connected WebSockets
  rect rgba(230,245,255,0.5)
  note right of WM: publishEvent
  Publisher->>WM: publishEvent(payload)
  loop For each WS with hibernationId
    WM->>WM: kickIfInvalid(ws)?
    alt Invalid (expired/revoked)
      WM-->>WS*: Close (4001/4003)
    else Valid
      WM-->>WS*: Send hibernation event
    end
  end
  end
Loading
sequenceDiagram
  autonumber
  participant WM as WebSocket Manager
  participant WS as WebSocket
  note right of WM: sendEventsAfter
  WM->>WM: kickIfInvalid(ws)?
  alt Invalid
    WM-->>WS: Close (4001/4003)
  else Valid
    WM->>WM: Load events after cursor
    WM-->>WS: Send events
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • unnoq/orpc#668 — Introduces/adjusts durable-event-iterator handler and websocket-manager paths that are directly modified here, indicating a continuation of that work.

Suggested labels

size:M

Poem

A whisk of time, a tick of clocks,
I hop through webs and token locks.
4001—expired, goodnight;
4003—revoked from sight.
Async breezes, events take flight—
I thump approval, ears alight.
🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @Rhayxz, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces robust JWT (JSON Web Token) expiry and revocation enforcement within the Durable Event Iterator (DEI) system. It ensures that WebSocket connections are validated against their JWTs both when events are published and during inbound RPC calls, enhancing security by automatically disconnecting clients with expired or revoked tokens.

Highlights

  • JWT Expiry Enforcement: WebSocket connections are now automatically closed with a 4001 status code if their associated JWT has expired.
  • Optional JWT Revocation Hook: A new shouldKickWs option allows for custom logic to revoke JWTs, closing connections with a 4003 status code.
  • Inbound RPC Call Protection: The durableEventIteratorRouter now validates the JWT of the current WebSocket connection before processing any inbound RPC calls, preventing unauthorized access.
  • Unified Token Validation Logic: A new kickIfInvalid method centralizes the logic for checking token validity (expiry and revocation) and closing invalid WebSocket connections.
  • Comprehensive Test Coverage: New and updated tests ensure the correct behavior of JWT expiry and revocation, including the proper closing of WebSocket connections.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces important security enhancements by enforcing JWT expiration and adding a mechanism for token revocation. The changes ensure that tokens are validated before processing RPC calls and when publishing events to websockets. New tests have been added to cover these scenarios, including checks for expired tokens. My main feedback is regarding error handling in the new token revocation hook, where silently swallowing errors could pose a security risk.

Comment on lines +68 to +71
try {
isRevoked = await this.options?.shouldKickWs?.(payload)
}
catch {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The try...catch block around the shouldKickWs call silently swallows any errors. This creates a "fail-open" security posture, where a failure in the revocation check (e.g., a database error) results in the token being treated as valid. This could allow users with revoked tokens to maintain access if the check mechanism fails.

At a minimum, the error should be logged to aid in debugging. For enhanced security, consider a "fail-closed" approach where an error during the revocation check causes the token to be treated as invalid.

The optional chaining (?.) on this.options?.shouldKickWs within the try block is also redundant given the if (this.options.shouldKickWs) check on the line above.

      try {
        isRevoked = await this.options.shouldKickWs(payload)
      }
      catch (e) {
        console.error('Error in `shouldKickWs` revocation check. Defaulting to not revoked.', e)
      }

Copy link
Copy Markdown

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/durable-event-iterator/src/durable-object/handler.test.ts (1)

10-16: Fix JWT time units in test (use seconds, not ms).

The router subscribes using new Date((payload.iat - 1) * 1000), assuming iat is seconds (JWT NumericDate). Here date = Date.now() makes iat/exp milliseconds, producing an incorrect “after” date. Align with seconds for consistency with kickIfInvalid and other tests.

Apply:

-  const date = Date.now()
+  const dateSec = Math.floor(Date.now() / 1000)

   const tokenPayload = {
     att: { some: 'attachment' },
-    iat: date,
-    exp: date + 1000,
+    iat: dateSec,
+    exp: dateSec + 1000,
     chn: 'test-channel',
     rpc: ['someMethod'],
   }
...
-        new Date((date - 1) * 1000),
+        new Date((dateSec - 1) * 1000),

Optionally freeze time with fake timers for determinism.

Also applies to: 49-53

packages/durable-event-iterator/src/durable-object/websocket-manager.ts (2)

122-131: Possible null deref if no prior attachment.

old = deserializeAttachment(ws) may be null/undefined (see tests’ stub). Accessing old[...] would throw. Default to {} and use optional chaining.

-  serializeAttachment(ws: WebSocket, attachment: TWsAttachment): void {
-    const old = this.deserializeAttachment(ws)
+  serializeAttachment(ws: WebSocket, attachment: TWsAttachment): void {
+    const old = this.deserializeAttachment(ws) ?? ({} as any)
     ws.serializeAttachment({
       ...attachment,
-      [DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY]: old[DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY],
-      [DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY]: old[DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY],
+      [DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY]: old?.[DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY],
+      [DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY]: old?.[DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY],
     })
   }

132-140: Object spread over possibly-null old can throw.

Spreading null/undefined results in a TypeError. Default old to {}.

-  serializeInternalAttachment(ws: WebSocket, attachment: Partial<DurableEventIteratorObjectWebsocketInternalAttachment<TTokenAttachment>>): void {
-    const old = this.deserializeAttachment(ws)
+  serializeInternalAttachment(ws: WebSocket, attachment: Partial<DurableEventIteratorObjectWebsocketInternalAttachment<TTokenAttachment>>): void {
+    const old = this.deserializeAttachment(ws) ?? ({} as any)
     ws.serializeAttachment({
-      ...old,
+      ...(old as any),
       [DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY]: attachment[DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY] ?? old?.[DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY],
       [DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY]: attachment[DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY] ?? old?.[DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY],
     })
   }
🧹 Nitpick comments (5)
packages/durable-event-iterator/src/durable-object/handler.ts (2)

43-48: Early invalid-token guard looks good.

Async kickIfInvalid gate before dispatch is correct and maps invalids to UNAUTHORIZED. Consider distinguishing expired vs revoked in the error message in future, if useful.


27-41: Guard against missing token payload in subscribe handler

It’s possible that deserializeAttachment(...)[DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY] comes back undefined, causing payload.iat to throw. Add a quick null check and early return before using the payload:

   subscribe: base.subscribe.handler(({ context, lastEventId }) => {
     return new HibernationEventIterator<any>((hibernationId) => {
       context.websocketManager.serializeInternalAttachment(context.currentWebsocket, {
         [DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY]: hibernationId,
       })

-      const payload = context.websocketManager.deserializeAttachment(context.currentWebsocket)[DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY]
+      const att = context.websocketManager.deserializeAttachment(context.currentWebsocket)
+      const payload = att?.[DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY]
+      if (!payload) {
+        // No token payload—nothing to replay
+        return
+      }

       context.websocketManager.sendEventsAfter(
         context.currentWebsocket,
         hibernationId,
         lastEventId !== undefined
           ? lastEventId
           : new Date((payload.iat - 1) * 1000),
       )
     })
   }),

– All existing uses of iat/exp have been confirmed to be in seconds per schema and tests; no further changes needed there.

packages/durable-event-iterator/src/durable-object/websocket-manager.test.ts (1)

1-271: Add a revocation test (4003) via shouldKickWs.

You added the hook; add one targeted test to lock behavior.

+it('publishEvent closes sockets when shouldKickWs revokes (4003)', async () => {
+  const ctx = createDurableObjectState()
+  const storage = new DurableEventIteratorObjectEventStorage(ctx)
+  const websocket = createCloudflareWebsocket()
+  ;(websocket as any).close = vi.fn()
+  const manager = new DurableEventIteratorObjectWebsocketManager<any, any, any>(
+    ctx, storage, { customJsonSerializers: [], shouldKickWs: () => true }
+  )
+  const nowSec = Math.floor(Date.now() / 1000)
+  manager.serializeInternalAttachment(websocket, {
+    [DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY]: { att: { att: true }, chn: 'chn', iat: nowSec, exp: nowSec + 3600, rpc: ['x'] },
+    [DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY]: 'hid',
+  })
+  await manager.publishEvent([websocket], { test: 'event' })
+  expect((websocket as any).close).toHaveBeenCalledWith(4003, 'token revoked')
+  expect(websocket.send).not.toHaveBeenCalled()
+})
packages/durable-event-iterator/src/durable-object/websocket-manager.ts (2)

85-99: Shield broadcast loops from ws.send exceptions.

A single bad socket send could abort the loop. Wrap sends to continue.

-      ws.send(encodeHibernationRPCEvent(hibernationEventIteratorId, payload, this.options))
+      try {
+        ws.send(encodeHibernationRPCEvent(hibernationEventIteratorId, payload, this.options))
+      } catch {}
...
-      ws.send(encodeHibernationRPCEvent(hibernationId, event, this.options))
+      try {
+        ws.send(encodeHibernationRPCEvent(hibernationId, event, this.options))
+      } catch {}

Also applies to: 109-120


8-11: Type hint: bind hook to the generic attachment type.

Minor: you could tie shouldKickWs to the manager’s generic TTokenAttachment to provide stronger typing for att.

-export interface DurableEventIteratorObjectWebsocketManagerOptions extends StandardRPCJsonSerializerOptions {
-  shouldKickWs?: (payload: DurableEventIteratorTokenPayload) => boolean | Promise<boolean>
+export interface DurableEventIteratorObjectWebsocketManagerOptions<TAtt = unknown> extends StandardRPCJsonSerializerOptions {
+  shouldKickWs?: (payload: DurableEventIteratorTokenPayload & { att: TAtt }) => boolean | Promise<boolean>
 }

…and pass TTokenAttachment when constructing options. Low priority.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7b2677a and 013e0a1.

📒 Files selected for processing (4)
  • packages/durable-event-iterator/src/durable-object/handler.test.ts (1 hunks)
  • packages/durable-event-iterator/src/durable-object/handler.ts (1 hunks)
  • packages/durable-event-iterator/src/durable-object/websocket-manager.test.ts (10 hunks)
  • packages/durable-event-iterator/src/durable-object/websocket-manager.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/durable-event-iterator/src/durable-object/websocket-manager.test.ts (4)
packages/durable-event-iterator/src/durable-object/consts.ts (2)
  • DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY (2-2)
  • DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY (1-1)
packages/durable-event-iterator/tests/shared.ts (2)
  • createDurableObjectState (3-24)
  • createCloudflareWebsocket (26-34)
packages/durable-event-iterator/src/durable-object/event-storage.ts (1)
  • DurableEventIteratorObjectEventStorage (23-145)
packages/durable-event-iterator/src/durable-object/websocket-manager.ts (1)
  • DurableEventIteratorObjectWebsocketManager (36-145)
packages/durable-event-iterator/src/durable-object/websocket-manager.ts (2)
packages/durable-event-iterator/src/schemas.ts (1)
  • DurableEventIteratorTokenPayload (3-3)
packages/durable-event-iterator/src/durable-object/consts.ts (2)
  • DURABLE_EVENT_ITERATOR_TOKEN_PAYLOAD_KEY (2-2)
  • DURABLE_EVENT_ITERATOR_HIBERNATION_ID_KEY (1-1)
🔇 Additional comments (5)
packages/durable-event-iterator/src/durable-object/websocket-manager.test.ts (4)

8-10: Mocking hibernation encoder is appropriate.
Keeps assertions focused on manager behavior.


24-26: Good switch to seconds-based iat/exp.
Matches runtime checks in kickIfInvalid.

Also applies to: 76-83, 140-149


166-225: Expiry path coverage (publishEvent) is solid.

Asserts 4001 close and skip-send. Nice use of fake timers.


227-271: Expiry path coverage (sendEventsAfter) is solid.

Verifies early return and 4001 close without sends.

packages/durable-event-iterator/src/durable-object/websocket-manager.ts (1)

47-83: kickIfInvalid implementation is correct and side-effect-safe.

Checks exp first, then optional revocation, and returns a boolean gate.

@codecov
Copy link
Copy Markdown

codecov Bot commented Aug 28, 2025

Codecov Report

❌ Patch coverage is 65.95745% with 16 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...t-iterator/src/durable-object/websocket-manager.ts 70.73% 12 Missing ⚠️
...rable-event-iterator/src/durable-object/handler.ts 33.33% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Aug 28, 2025

More templates

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@939

@orpc/client

npm i https://pkg.pr.new/@orpc/client@939

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@939

@orpc/experimental-durable-event-iterator

npm i https://pkg.pr.new/@orpc/experimental-durable-event-iterator@939

@orpc/hey-api

npm i https://pkg.pr.new/@orpc/hey-api@939

@orpc/interop

npm i https://pkg.pr.new/@orpc/interop@939

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@939

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@939

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@939

@orpc/openapi-client

npm i https://pkg.pr.new/@orpc/openapi-client@939

@orpc/otel

npm i https://pkg.pr.new/@orpc/otel@939

@orpc/react

npm i https://pkg.pr.new/@orpc/react@939

@orpc/react-query

npm i https://pkg.pr.new/@orpc/react-query@939

@orpc/experimental-react-swr

npm i https://pkg.pr.new/@orpc/experimental-react-swr@939

@orpc/server

npm i https://pkg.pr.new/@orpc/server@939

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@939

@orpc/solid-query

npm i https://pkg.pr.new/@orpc/solid-query@939

@orpc/standard-server

npm i https://pkg.pr.new/@orpc/standard-server@939

@orpc/standard-server-aws-lambda

npm i https://pkg.pr.new/@orpc/standard-server-aws-lambda@939

@orpc/standard-server-fetch

npm i https://pkg.pr.new/@orpc/standard-server-fetch@939

@orpc/standard-server-node

npm i https://pkg.pr.new/@orpc/standard-server-node@939

@orpc/standard-server-peer

npm i https://pkg.pr.new/@orpc/standard-server-peer@939

@orpc/svelte-query

npm i https://pkg.pr.new/@orpc/svelte-query@939

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@939

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@939

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@939

@orpc/vue-colada

npm i https://pkg.pr.new/@orpc/vue-colada@939

@orpc/vue-query

npm i https://pkg.pr.new/@orpc/vue-query@939

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@939

commit: 013e0a1

@dinwwwh
Copy link
Copy Markdown
Member

dinwwwh commented Aug 28, 2025

Your approach still missing some cases. For example, a procedure can return an Event Iterator. Currently, you only check it on the first call, while an Event Iterator can live for a long time, especially with a Hibernation Event Iterator.

Maybe I can work on this soon to improve the DX with a proxy, so every time a WebSocket message is sent or received, it will be checked

@Rhayxz
Copy link
Copy Markdown
Author

Rhayxz commented Aug 28, 2025

Your approach still missing some cases. For example, a procedure can return an Event Iterator. Currently, you only check it on the first call, while an Event Iterator can live for a long time, especially with a Hibernation Event Iterator.

Maybe I can work on this soon to improve the DX with a proxy, so every time a WebSocket message is sent or received, it will be checked

Yes please, I tried to touch some event iterator code, but ended up running into a few issues as I'm quite unfamiliar how the ORPC event iterators work under the hood.

@dinwwwh
Copy link
Copy Markdown
Member

dinwwwh commented Sep 14, 2025

I've created #965 with a different approach that better addresses this issue.

@dinwwwh dinwwwh closed this Sep 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants