@copilotkit/react-core 1.57.2 → 1.57.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@copilotkit/react-core",
3
- "version": "1.57.2",
3
+ "version": "1.57.3",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "ai",
@@ -81,11 +81,11 @@
81
81
  "untruncate-json": "^0.0.1",
82
82
  "use-stick-to-bottom": "^1.1.1",
83
83
  "zod-to-json-schema": "^3.24.5",
84
- "@copilotkit/core": "1.57.2",
85
- "@copilotkit/shared": "1.57.2",
86
- "@copilotkit/web-inspector": "1.57.2",
87
- "@copilotkit/runtime-client-gql": "1.57.2",
88
- "@copilotkit/a2ui-renderer": "1.57.2"
84
+ "@copilotkit/a2ui-renderer": "1.57.3",
85
+ "@copilotkit/core": "1.57.3",
86
+ "@copilotkit/runtime-client-gql": "1.57.3",
87
+ "@copilotkit/shared": "1.57.3",
88
+ "@copilotkit/web-inspector": "1.57.3"
89
89
  },
90
90
  "devDependencies": {
91
91
  "@tailwindcss/cli": "^4.1.11",
@@ -115,17 +115,58 @@ describe("CopilotChat perf — re-render regression", () => {
115
115
  renderCounts.clear();
116
116
  });
117
117
 
118
- // TanStack Virtual schedules rAF callbacks for measurement. On Node 20 the
119
- // jsdom timing is different — draining a fixed number of rAF rounds is not
120
- // enough because the observer keeps scheduling new callbacks. When
121
- // @testing-library/react's auto-cleanup unmounts the component AFTER our
122
- // afterEach, any pending rAF fires against a torn-down window (null) and
123
- // throws: TypeError: Cannot read properties of null ('requestAnimationFrame').
118
+ // @tanstack/virtual-core 3.13.18 has a latent bug: `scrollToIndex` schedules
119
+ // a nested rAF that calls `this.targetWindow.requestAnimationFrame(verify)`
120
+ // with no null-check. The virtualizer's cleanup (run on React unmount) sets
121
+ // `targetWindow = null`, so if the outer rAF fires after unmount, the inner
122
+ // schedule throws `Cannot read properties of null (reading 'requestAnimationFrame')`.
124
123
  //
125
- // Fix: after draining what we can, replace rAF with a no-op so any callback
126
- // scheduled during (or after) RTL cleanup is silently swallowed. Restore the
127
- // real rAF at the start of the next test via beforeEach.
124
+ // Vitest reports this as an unhandled error and exits non-zero even though
125
+ // every test passes. We wrap rAF (on BOTH globalThis and window — they're
126
+ // separate bindings in vitest+jsdom; tanstack uses `targetWindow.rAF` which
127
+ // resolves to `window.rAF`) so callbacks that hit the known tanstack bug
128
+ // are swallowed. After each test we drain pending callbacks and replace rAF
129
+ // with a no-op to keep stragglers from leaking into the next test.
128
130
  const realRAF = globalThis.requestAnimationFrame;
131
+ const realWindowRAF =
132
+ typeof window !== "undefined" ? window.requestAnimationFrame : realRAF;
133
+
134
+ const isKnownTanstackTeardownError = (err: unknown): boolean => {
135
+ const message =
136
+ (err as { message?: string } | null | undefined)?.message ?? "";
137
+ return (
138
+ message.includes("Cannot read properties of null") &&
139
+ message.includes("requestAnimationFrame")
140
+ );
141
+ };
142
+
143
+ const wrapRAF = (real: typeof requestAnimationFrame) =>
144
+ ((cb: FrameRequestCallback) =>
145
+ real((time) => {
146
+ try {
147
+ cb(time);
148
+ } catch (err) {
149
+ if (isKnownTanstackTeardownError(err)) return;
150
+ throw err;
151
+ }
152
+ })) as typeof requestAnimationFrame;
153
+
154
+ const noopRAF = ((_cb: FrameRequestCallback) =>
155
+ 0) as typeof requestAnimationFrame;
156
+
157
+ const installSafeRAF = () => {
158
+ globalThis.requestAnimationFrame = wrapRAF(realRAF);
159
+ if (typeof window !== "undefined") {
160
+ window.requestAnimationFrame = wrapRAF(realWindowRAF);
161
+ }
162
+ };
163
+
164
+ const installNoopRAF = () => {
165
+ globalThis.requestAnimationFrame = noopRAF;
166
+ if (typeof window !== "undefined") {
167
+ window.requestAnimationFrame = noopRAF;
168
+ }
169
+ };
129
170
 
130
171
  afterEach(async () => {
131
172
  // Best-effort drain of already-queued rAF callbacks.
@@ -134,13 +175,12 @@ describe("CopilotChat perf — re-render regression", () => {
134
175
  await new Promise<void>((r) => realRAF(() => r()));
135
176
  });
136
177
  // Neuter rAF so callbacks scheduled during RTL cleanup are harmless.
137
- globalThis.requestAnimationFrame = ((_cb: FrameRequestCallback) =>
138
- 0) as typeof requestAnimationFrame;
178
+ installNoopRAF();
139
179
  });
140
180
 
141
181
  beforeEach(() => {
142
- // Restore real rAF for the upcoming test.
143
- globalThis.requestAnimationFrame = realRAF;
182
+ // Install the error-swallowing wrap on rAF for the upcoming test.
183
+ installSafeRAF();
144
184
  });
145
185
 
146
186
  it("completed messages do not re-render when a new message is added", async () => {