Skip to content

fix(standard-server): optimize withEventMeta to avoid unnecessary proxies event iterator data - #979

Merged
dinwwwh merged 3 commits into
mainfrom
unnoq/issue977
Sep 11, 2025
Merged

fix(standard-server): optimize withEventMeta to avoid unnecessary proxies event iterator data#979
dinwwwh merged 3 commits into
mainfrom
unnoq/issue977

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Sep 10, 2025

Copy link
Copy Markdown
Member

This prevents structuredClone failures on proxy things
Fixes: #977

Summary by CodeRabbit

  • Performance
    • Skips metadata processing when no meaningful event metadata is present, reducing overhead while preserving existing behavior.
  • Tests
    • Added tests covering cases where metadata should be applied vs. bypassed to ensure consistent, efficient handling.

…xies

This prevents structuredClone failures on proxy things
Fixes: #977
@vercel

vercel Bot commented Sep 10, 2025

Copy link
Copy Markdown

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

Project Deployment Preview Comments Updated (UTC)
orpc Ready Ready Preview Comment Sep 10, 2025 3:15am

@coderabbitai

coderabbitai Bot commented Sep 10, 2025

Copy link
Copy Markdown

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds an early-return in withEventMeta to avoid creating a Proxy when meta has no meaningful fields (id, retry, comments empty/undefined), and adds tests verifying when the original object is returned versus a proxied/new object. No public API or exported signatures changed.

Changes

Cohort / File(s) Summary
Event meta runtime change & tests
packages/standard-server/src/event-iterator/meta.ts, packages/standard-server/src/event-iterator/meta.test.ts
Add early return in withEventMeta when meta.id, meta.retry are undefined and meta.comments is empty/undefined, skipping assertions and Proxy wrapping; expand tests to assert same-reference vs new-object behavior across various meta inputs (including edge cases like id: '', retry: 0, comments: [''], unknown keys, and undefined fields).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Caller
  participant withEventMeta
  participant Validations as Validations<br/>(id/retry/comments)
  participant ProxyWrap as Proxy Wrapper

  Caller->>withEventMeta: withEventMeta(container, meta)

  alt meta.id/retry undefined AND meta.comments empty/undefined
    withEventMeta-->>Caller: return container (same reference)
    note right of withEventMeta #DFF2E1: Skip validations & Proxy
  else meta has meaningful fields
    withEventMeta->>Validations: assertEventId / assertEventRetry / assertEventComment
    Validations-->>withEventMeta: validations pass
    withEventMeta->>ProxyWrap: create Proxy and attach EVENT_SOURCE_META_SYMBOL
    ProxyWrap-->>Caller: return proxied container
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • unnoq/orpc#477 — Touches the same event-metadata helpers (withEventMeta/getEventMeta) and relates to avoiding Proxy-wrapped events that break consumers expecting plain objects.

Pre-merge checks (4 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title directly summarizes the primary change by stating that withEventMeta is optimized to avoid unnecessary proxies on event iterator data, which aligns with the core update implemented in this pull request.
Linked Issues Check ✅ Passed The pull request implements an early return in withEventMeta to skip Proxy creation when no metadata is provided, ensuring that event iterator values remain plain objects and thus preventing the structuredClone failures described in issue #977, and the added tests verify both proxy and no-proxy scenarios as required.
Out of Scope Changes Check ✅ Passed All code modifications are limited to the withEventMeta function and its tests in the event-iterator module, directly targeting the linked issue without introducing unrelated changes elsewhere in the codebase.

Poem

🐰 A tiny hop, no Proxy veil,
If meta’s bare I leave the trail.
But give me ids or comments bright,
I don a coat and hold it tight.
Hooray—plain parts, or dressed just right.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67af6c8 and c547f7d.

📒 Files selected for processing (2)
  • packages/standard-server/src/event-iterator/meta.test.ts (1 hunks)
  • packages/standard-server/src/event-iterator/meta.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/standard-server/src/event-iterator/meta.test.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: publish-commit
  • GitHub Check: test
  • GitHub Check: lint
🔇 Additional comments (2)
packages/standard-server/src/event-iterator/meta.ts (2)

10-16: Good guard: avoids proxy when meta is effectively empty.

The early-return with optional chaining matches the intent and prevents unnecessary Proxy creation. Nice.


43-47: No action needed: getEventMeta’s return change is safe
All existing call-sites either guard on meta truthiness (e.g. if (meta && …)) or use optional chaining/nullish checks, and tests already expect undefined for empty meta—so returning undefined instead of {} has no adverse impact.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch unnoq/issue977

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.

@dosubot dosubot Bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Sep 10, 2025

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

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.

Summary of Changes

Hello @unnoq, 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 an optimization to the withEventMeta function within the standard-server package. The primary goal is to enhance efficiency and prevent potential issues by ensuring that proxy objects are only created when there are actual metadata changes to apply. This refinement helps avoid structuredClone failures that could arise from attempting to clone objects that were unnecessarily proxied.

Highlights

  • Optimization of withEventMeta function: The withEventMeta function now includes a check to prevent the creation of unnecessary proxy objects when no actual event metadata (id, retry, or comments) is being applied. This ensures that the original object reference is returned if no metadata changes are required.
  • Prevention of structuredClone failures: By avoiding the creation of superfluous proxy objects, this change directly addresses and prevents potential structuredClone failures that could occur when attempting to deep copy objects that were inadvertently proxied by withEventMeta without any meaningful metadata modifications.
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.

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

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.

Code Review

This pull request introduces a valuable optimization to withEventMeta by avoiding the creation of a Proxy when no metadata is provided. This not only improves performance but also resolves a structuredClone failure on proxied objects. The implementation is sound and is accompanied by appropriate tests. I have one suggestion to enhance the code's conciseness.

Comment thread packages/standard-server/src/event-iterator/meta.ts Outdated
@codecov

codecov Bot commented Sep 10, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@pkg-pr-new

pkg-pr-new Bot commented Sep 10, 2025

Copy link
Copy Markdown
More templates

@orpc/arktype

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

@orpc/client

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

@orpc/contract

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

@orpc/experimental-durable-event-iterator

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

@orpc/hey-api

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

@orpc/interop

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

@orpc/json-schema

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

@orpc/nest

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

@orpc/openapi

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

@orpc/openapi-client

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

@orpc/otel

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

@orpc/react

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

@orpc/react-query

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

@orpc/experimental-react-swr

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

@orpc/server

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

@orpc/shared

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

@orpc/solid-query

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

@orpc/standard-server

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

@orpc/standard-server-aws-lambda

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

@orpc/standard-server-fetch

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

@orpc/standard-server-node

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

@orpc/standard-server-peer

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

@orpc/svelte-query

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

@orpc/tanstack-query

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

@orpc/trpc

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

@orpc/valibot

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

@orpc/vue-colada

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

@orpc/vue-query

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

@orpc/zod

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

commit: c547f7d

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/standard-server/src/event-iterator/meta.ts (1)

10-16: Tighten the “empty meta” check (readability).

Use optional chaining + nullish coalescing to express “undefined or empty” succinctly.

Apply:

-  if (
-    meta.id === undefined
-    && meta.retry === undefined
-    && (meta.comments === undefined || meta.comments.length === 0)
-  ) {
+  if (
+    meta.id === undefined
+    && meta.retry === undefined
+    && ((meta.comments?.length ?? 0) === 0)
+  ) {
     return container
   }
🧹 Nitpick comments (3)
packages/standard-server/src/event-iterator/meta.ts (2)

26-30: Guard against non-array comments at runtime.

If comments is accidentally a string in JS callers, the for-of loop will iterate characters. Add a shape check.

Apply:

   if (meta.comments !== undefined) {
+    if (!Array.isArray(meta.comments)) {
+      throw new TypeError("Event's comments must be an array of strings")
+    }
     for (const comment of meta.comments) {
       assertEventComment(comment)
     }
   }

32-40: Consider eliminating Proxy entirely with a WeakMap-backed meta store.

If any meaningful meta reaches consumer-visible values, Proxies will still break structuredClone. A WeakMap keeps metadata without wrapping or mutating (GC-safe), and getEventMeta can read from it.

Example (outside the shown diff):

// module scope
const META = new WeakMap<object, EventMeta>()

export function withEventMeta<T extends object>(container: T, meta: EventMeta): T {
  if (meta.id === undefined && meta.retry === undefined && ((meta.comments?.length ?? 0) === 0)) {
    return container
  }
  // run validations...
  META.set(container, meta)
  return container
}

export function getEventMeta(container: unknown): EventMeta | undefined {
  return isTypescriptObject(container) ? META.get(container as object) : undefined
}
packages/standard-server/src/event-iterator/meta.test.ts (1)

19-29: Strengthen cases + fix test title grammar.

Add coverage for retry: 0 and “comments-only” paths; tweak title for grammar.

Apply:

-it('withEventMeta only proxy when make sense', () => {
+it('withEventMeta only proxies when it makes sense', () => {
   const data = { value: 123, meta: undefined }

   expect(withEventMeta(data, { id: '123', retry: 10000, comments: ['hello', 'world'] })).not.toBe(data)
   expect(withEventMeta(data, { id: '123' })).not.toBe(data)

   expect(withEventMeta(data, {})).toBe(data)
   expect(withEventMeta(data, { notExists: true } as any)).toBe(data)
   expect(withEventMeta(data, { id: undefined })).toBe(data)
   expect(withEventMeta(data, { comments: [] })).toBe(data)
+  expect(withEventMeta(data, { retry: 0 })).not.toBe(data)
+  expect(withEventMeta(data, { comments: ['note'] })).not.toBe(data)
 })

Optional: add a separate assertion that structuredClone(withEventMeta(data, {})) does not throw, to lock in the fix for empty-meta cases.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 316d5b9 and 67af6c8.

📒 Files selected for processing (2)
  • packages/standard-server/src/event-iterator/meta.test.ts (1 hunks)
  • packages/standard-server/src/event-iterator/meta.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/standard-server/src/event-iterator/meta.test.ts (1)
packages/standard-server/src/event-iterator/meta.ts (1)
  • withEventMeta (9-41)
🔇 Additional comments (1)
packages/standard-server/src/event-iterator/meta.ts (1)

10-16: Approve withEventMeta early-return fix. Verified that all withEventMeta call sites use non-empty meta when proxying and no structuredClone usages exist to rewrap plain events.

@dinwwwh dinwwwh added the lgtm This PR has been approved by a maintainer label Sep 10, 2025
@dinwwwh
dinwwwh merged commit cedbd4c into main Sep 11, 2025
11 checks passed
@dinwwwh
dinwwwh deleted the unnoq/issue977 branch June 22, 2026 01:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Client event iterator returns proxy events breaking applications that exepect structuredClone to work

1 participant