@marimo-team/islands 0.25.3-dev157 → 0.25.3-dev162

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.
@@ -1,6 +1,6 @@
1
1
  import { a as e } from "./rolldown-runtime-Cb76FRpK.js";
2
2
  import { t } from "./react-sHtZdjeP.js";
3
- import { a as n } from "./glide-data-editor-DZHp-j3z.js";
3
+ import { a as n } from "./glide-data-editor-Dn1Ekucb.js";
4
4
  //#region ../node_modules/.pnpm/@glideapps+glide-data-grid@6.0.4-alpha24_lodash@4.17.21_marked@15.0.12_react-dom@19.3.0_27cffe7f1bc30287d59ac27db3240c5b/node_modules/@glideapps/glide-data-grid/dist/esm/internal/data-grid-overlay-editor/private/number-overlay-editor-style.js
5
5
  var r = /* @__PURE__ */ e(t()), i = /*#__PURE__*/ n("div")({
6
6
  name: "NumberOverlayEditorStyle",
@@ -4,14 +4,14 @@ import { t as o } from "./react-sHtZdjeP.js";
4
4
  import { t as s } from "./compiler-runtime-CldRdSsv.js";
5
5
  import { m as c, t as l } from "./tooltip-CJ4Rqasp.js";
6
6
  import { k as u } from "./error-entries-BpUJSLUZ.js";
7
- import { $ as d, Q as f, Z as p, an as m, i as h, l as g, ln as _, n as v, on as y, r as b, t as x, u as S } from "./common-DNumU4vH.js";
7
+ import { $ as d, Q as f, Z as p, an as m, i as h, l as g, ln as _, n as v, on as y, r as b, t as x, u as S } from "./common-BmlT-bPP.js";
8
8
  import { M as C } from "./select-CkF_GBxO.js";
9
9
  import { J as ee } from "./dropdown-menu-BWnnAstC.js";
10
10
  import { _ as w } from "./toDate-rySyYxqk.js";
11
11
  import { t as T } from "./jsx-runtime-3BD1kT0s.js";
12
12
  import { q as E } from "./use-restore-focus-CmGwRNId.js";
13
13
  import { A as D, C as O, b as k } from "./useTheme-TLkqJsvo.js";
14
- import { a as A, n as te, t as ne } from "./code-visibility-sg6NMHZ9.js";
14
+ import { a as A, n as te, t as ne } from "./code-visibility-DEIiTBMH.js";
15
15
  /* empty css */
16
16
  var j = c("sticky-note", [["path", {
17
17
  d: "M21 9a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 15 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2z",
@@ -12,11 +12,11 @@ import { c as m, t as h } from "./arrays-R6JsImiT.js";
12
12
  import { t as te } from "./objects-DCmMvZtn.js";
13
13
  import { t as ne } from "./useAsyncData-B7MiltyV.js";
14
14
  import { a as g, i as re, n as ie, t as ae } from "./formats-CwJHWasD.js";
15
- import { D as oe, n as _ } from "./vega-loader.browser-B9Pz0EGP.js";
16
- import { t as se } from "./react-vega-C4T9Rb_w.js";
17
- import { a as ce, n as le } from "./loader-DOVB0Syl.js";
15
+ import { t as _ } from "./semaphore-89jsoHtS.js";
16
+ import { D as oe, n as se } from "./vega-loader.browser-B9Pz0EGP.js";
17
+ import { t as ce } from "./react-vega-C4T9Rb_w.js";
18
+ import { a as le, n as v } from "./loader-DOVB0Syl.js";
18
19
  import { t as ue } from "./useDeepCompareMemoize-DZmHBD_1.js";
19
- import { t as v } from "./semaphore-89jsoHtS.js";
20
20
  import { t as de } from "./use-vega-container-remeasure-Bz4PZMtt.js";
21
21
  //#region src/plugins/impl/vega/fix-relative-url.ts
22
22
  var fe = /* @__PURE__ */ e(a(), 1), pe = o();
@@ -463,7 +463,7 @@ function H(e) {
463
463
  var U = 5;
464
464
  async function W(e) {
465
465
  if (!e) return e;
466
- let t = "datasets" in e ? { ...e.datasets } : {}, n = new v(U), r = async (e) => {
466
+ let t = "datasets" in e ? { ...e.datasets } : {}, n = new _(U), r = async (e) => {
467
467
  if (!e) return e;
468
468
  if ("layer" in e) {
469
469
  let t = await Promise.all(e.layer.map(r));
@@ -496,7 +496,7 @@ async function W(e) {
496
496
  } catch {
497
497
  return e;
498
498
  }
499
- let a = e.data.format, o = await n.run(() => le(i.href, a));
499
+ let a = e.data.format, o = await n.run(() => v(i.href, a));
500
500
  return t[i.pathname] = o, {
501
501
  ...e,
502
502
  data: { name: i.pathname }
@@ -510,7 +510,7 @@ async function W(e) {
510
510
  //#endregion
511
511
  //#region src/plugins/impl/vega/vega-component.tsx
512
512
  var G = u();
513
- _("arrow", ae);
513
+ se("arrow", ae);
514
514
  var K = (e) => {
515
515
  let t = (0, pe.c)(12), { value: n, setValue: r, chartSelection: i, fieldSelection: a, spec: o, embedOptions: s } = e, c, l;
516
516
  t[0] === o ? (c = t[1], l = t[2]) : (c = async () => W(o), l = [o], t[0] = o, t[1] = c, t[2] = l);
@@ -530,7 +530,7 @@ var K = (e) => {
530
530
  embedOptions: s
531
531
  }), t[5] = i, t[6] = s, t[7] = a, t[8] = u, t[9] = r, t[10] = n, t[11] = p) : p = t[11], p;
532
532
  }, q = (e) => {
533
- let a = (0, pe.c)(50), { value: o, setValue: l, chartSelection: u, fieldSelection: d, spec: m, embedOptions: h } = e, { theme: ne } = ee(), g = (0, fe.useRef)(null), ae = (0, fe.useRef)(void 0), [_, le] = (0, fe.useState)(), v;
533
+ let a = (0, pe.c)(50), { value: o, setValue: l, chartSelection: u, fieldSelection: d, spec: m, embedOptions: h } = e, { theme: ne } = ee(), g = (0, fe.useRef)(null), ae = (0, fe.useRef)(void 0), [_, se] = (0, fe.useState)(), v;
534
534
  bb0: {
535
535
  if (h && "actions" in h) {
536
536
  v = h.actions;
@@ -572,11 +572,11 @@ var K = (e) => {
572
572
  } else M = a[14];
573
573
  let N = M, P;
574
574
  a[17] === C ? P = a[18] : (P = (e) => {
575
- t.error(e), t.debug(C), le(e);
575
+ t.error(e), t.debug(C), se(e);
576
576
  }, a[17] = C, a[18] = P);
577
577
  let F = p(P), I;
578
578
  a[19] === Symbol.for("react.memo_cache_sentinel") ? (I = (e) => {
579
- t.debug("[Vega view] created", e), ae.current = e, le(void 0);
579
+ t.debug("[Vega view] created", e), ae.current = e, se(void 0);
580
580
  }, a[19] = I) : I = a[19];
581
581
  let L = p(I), R;
582
582
  a[20] === T ? R = a[21] : (R = () => {
@@ -600,7 +600,7 @@ var K = (e) => {
600
600
  theme: B,
601
601
  actions: y,
602
602
  mode: "vega-lite",
603
- tooltip: ce.call,
603
+ tooltip: le.call,
604
604
  renderer: "canvas"
605
605
  }, a[22] = y, a[23] = B, a[24] = V) : V = a[24];
606
606
  let H;
@@ -611,7 +611,7 @@ var K = (e) => {
611
611
  onError: F,
612
612
  onEmbed: L
613
613
  }, a[25] = F, a[26] = L, a[27] = C, a[28] = V, a[29] = H) : H = a[29];
614
- let U = se(H), W;
614
+ let U = ce(H), W;
615
615
  a[30] === C ? W = a[31] : (W = oe(C), a[30] = C, a[31] = W);
616
616
  let K = W;
617
617
  de(g, K === "container");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.25.3-dev157",
3
+ "version": "0.25.3-dev162",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -0,0 +1,117 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { markdownLanguage } from "@codemirror/lang-markdown";
4
+ import { hoverResource, type Resource } from "@marimo-team/codemirror-mcp";
5
+ import { createStore } from "jotai";
6
+ import { assert, beforeEach, describe, expect, it, vi } from "vitest";
7
+ import { MockNotebook } from "@/__mocks__/notebook";
8
+ import { getAIContextRegistry } from "@/core/ai/context/context";
9
+ import { ErrorContextProvider } from "@/core/ai/context/providers/error";
10
+ import { AIContextRegistry } from "@/core/ai/context/registry";
11
+ import { notebookAtom } from "@/core/cells/cells";
12
+ import { CellId } from "@/core/cells/ids";
13
+ import { resourceExtension } from "../resources";
14
+
15
+ vi.mock("@marimo-team/codemirror-mcp", async (importOriginal) => ({
16
+ ...(await importOriginal<typeof import("@marimo-team/codemirror-mcp")>()),
17
+ hoverResource: vi.fn(() => []),
18
+ }));
19
+
20
+ vi.mock("@/core/ai/context/context", () => ({
21
+ getAIContextRegistry: vi.fn(),
22
+ }));
23
+
24
+ describe("resource tooltips", () => {
25
+ const message = '<b>Unexpected response</b> &amp; "details"';
26
+ let provider: ErrorContextProvider;
27
+ let resource: Resource;
28
+
29
+ beforeEach(() => {
30
+ vi.clearAllMocks();
31
+ const store = createStore();
32
+ store.set(
33
+ notebookAtom,
34
+ MockNotebook.notebookStateWithErrors([
35
+ {
36
+ cellId: CellId.create(),
37
+ cellName: "Cell 1",
38
+ errorData: [MockNotebook.errors.exception(message)],
39
+ },
40
+ ]),
41
+ );
42
+ provider = new ErrorContextProvider(store);
43
+ resource = provider.getItems()[1];
44
+ vi.mocked(getAIContextRegistry).mockReturnValue(
45
+ new AIContextRegistry().register(provider),
46
+ );
47
+ resourceExtension({ language: markdownLanguage, store });
48
+ });
49
+
50
+ function renderTooltip(item = resource) {
51
+ const options = vi.mocked(hoverResource).mock.calls[0][0];
52
+ assert(options.createTooltip);
53
+ return options.createTooltip(item).dom;
54
+ }
55
+
56
+ it("preserves literal text in cell error descriptions", () => {
57
+ const dom = renderTooltip();
58
+ expect(dom.textContent).toBe(message);
59
+ expect(dom.childElementCount).toBe(0);
60
+ });
61
+
62
+ it("preserves literal descriptions when a provider is unavailable", () => {
63
+ const dom = renderTooltip({ ...resource, type: "unknown" });
64
+ expect(dom.textContent).toBe(message);
65
+ expect(dom.childElementCount).toBe(0);
66
+ });
67
+
68
+ it("falls back to the literal resource name", () => {
69
+ const dom = renderTooltip({
70
+ ...resource,
71
+ description: undefined,
72
+ name: message,
73
+ });
74
+ expect(dom.textContent).toBe(message);
75
+ expect(dom.childElementCount).toBe(0);
76
+ });
77
+
78
+ it("preserves literal text in completion info strings", () => {
79
+ vi.spyOn(provider, "formatCompletion").mockReturnValue({
80
+ label: "Error",
81
+ info: message,
82
+ });
83
+ const dom = renderTooltip({ ...resource, description: "Fallback" });
84
+ expect(dom.textContent).toBe(message);
85
+ expect(dom.childElementCount).toBe(0);
86
+ });
87
+
88
+ it("preserves literal fallback text when an info renderer returns null", () => {
89
+ vi.spyOn(provider, "formatCompletion").mockReturnValue({
90
+ label: "Error",
91
+ info: () => null,
92
+ });
93
+ const dom = renderTooltip();
94
+ expect(dom.textContent).toBe(message);
95
+ expect(dom.childElementCount).toBe(0);
96
+ });
97
+
98
+ it("preserves literal fallback text for async info renderers", () => {
99
+ vi.spyOn(provider, "formatCompletion").mockReturnValue({
100
+ label: "Error",
101
+ info: async () => document.createElement("div"),
102
+ });
103
+ const dom = renderTooltip();
104
+ expect(dom.textContent).toBe(message);
105
+ expect(dom.childElementCount).toBe(0);
106
+ });
107
+
108
+ it.each(["element", "tooltip"])("preserves custom %s renderers", (kind) => {
109
+ const dom = document.createElement("strong");
110
+ dom.textContent = "Details";
111
+ vi.spyOn(provider, "formatCompletion").mockReturnValue({
112
+ label: "Error",
113
+ info: () => (kind === "element" ? dom : { dom }),
114
+ });
115
+ expect(renderTooltip()).toBe(dom);
116
+ });
117
+ });
@@ -142,7 +142,7 @@ export function resourceExtension(opts: {
142
142
 
143
143
  function asDom(value: string): TooltipView {
144
144
  const tooltip = document.createElement("div");
145
- tooltip.innerHTML = value;
145
+ tooltip.textContent = value;
146
146
  return {
147
147
  dom: tooltip,
148
148
  };
@@ -8,6 +8,8 @@ import {
8
8
  type MockInstance,
9
9
  vi,
10
10
  } from "vitest";
11
+ import { Deferred } from "@/utils/Deferred";
12
+ import { Logger } from "@/utils/Logger";
11
13
  import { getMarimoInternal, Model } from "../model";
12
14
  import { handleWidgetMessage, WidgetRegistry } from "../registry";
13
15
  import type { EsmSpec, ModelState, WidgetModelId } from "../types";
@@ -155,6 +157,155 @@ describe("WidgetRegistry models", () => {
155
157
  );
156
158
  });
157
159
 
160
+ describe("outgoing messages", () => {
161
+ async function openModel(id = testId) {
162
+ await handleWidgetMessage(registry, {
163
+ model_id: id,
164
+ message: {
165
+ method: "open",
166
+ state: {},
167
+ buffer_paths: [],
168
+ buffers: [],
169
+ },
170
+ });
171
+ return registry.getModel(id);
172
+ }
173
+
174
+ afterEach(() => {
175
+ mockSendModelValue.mockReset().mockResolvedValue(null);
176
+ vi.restoreAllMocks();
177
+ });
178
+
179
+ it("waits for each acknowledgement before sending the next update", async () => {
180
+ const model = await openModel();
181
+ const responses = [new Deferred<null>(), new Deferred<null>()];
182
+ for (const response of responses) {
183
+ mockSendModelValue.mockReturnValueOnce(response.promise);
184
+ }
185
+ const states = [
186
+ { card: "A", seq: 5 },
187
+ { card: "", seq: 6 },
188
+ { card: "B", seq: 7 },
189
+ ];
190
+ for (const state of states) {
191
+ model.set("selection", state);
192
+ model.save_changes();
193
+ }
194
+
195
+ await vi.waitFor(() =>
196
+ expect(mockSendModelValue).toHaveBeenCalledTimes(1),
197
+ );
198
+ for (const [index, response] of responses.entries()) {
199
+ response.resolve(null);
200
+ await vi.waitFor(() =>
201
+ expect(mockSendModelValue).toHaveBeenCalledTimes(index + 2),
202
+ );
203
+ }
204
+ expect(mockSendModelValue.mock.calls).toEqual(
205
+ states.map((selection) => [
206
+ {
207
+ modelId: testId,
208
+ message: {
209
+ method: "update",
210
+ state: { selection },
211
+ bufferPaths: [],
212
+ },
213
+ buffers: [],
214
+ },
215
+ ]),
216
+ );
217
+ });
218
+
219
+ it("orders custom messages with updates and waits before calling callbacks", async () => {
220
+ const model = await openModel();
221
+ const response = new Deferred<null>();
222
+ mockSendModelValue.mockReturnValueOnce(response.promise);
223
+ const callback = vi.fn();
224
+ const sent = model.send({ action: "first" }, callback);
225
+ model.set("count", 1);
226
+ model.save_changes();
227
+ const last = model.send({ action: "last" });
228
+
229
+ await vi.waitFor(() =>
230
+ expect(mockSendModelValue).toHaveBeenCalledTimes(1),
231
+ );
232
+ expect(callback).not.toHaveBeenCalled();
233
+ response.resolve(null);
234
+ await Promise.all([sent, last]);
235
+ expect(callback).toHaveBeenCalledExactlyOnceWith();
236
+ expect(
237
+ mockSendModelValue.mock.calls.map(([request]) => request.message),
238
+ ).toEqual([
239
+ { method: "custom", content: { action: "first" } },
240
+ { method: "update", state: { count: 1 }, bufferPaths: [] },
241
+ { method: "custom", content: { action: "last" } },
242
+ ]);
243
+ });
244
+
245
+ it("continues sending after a failed update", async () => {
246
+ const model = await openModel();
247
+ const response = new Deferred<null>();
248
+ mockSendModelValue.mockReturnValueOnce(response.promise);
249
+ const logError = vi
250
+ .spyOn(Logger, "error")
251
+ .mockImplementation(() => undefined);
252
+ model.set("count", 1);
253
+ model.save_changes();
254
+ model.set("count", 2);
255
+ model.save_changes();
256
+ const last = model.send({ action: "done" });
257
+
258
+ await vi.waitFor(() =>
259
+ expect(mockSendModelValue).toHaveBeenCalledTimes(1),
260
+ );
261
+ const error = new Error("Network failure");
262
+ response.reject(error);
263
+ await last;
264
+ expect(mockSendModelValue).toHaveBeenCalledTimes(3);
265
+ expect(logError).toHaveBeenCalledWith(
266
+ "[anywidget] Failed to save model changes",
267
+ error,
268
+ );
269
+ });
270
+
271
+ it("allows different models to send independently", async () => {
272
+ const first = await openModel();
273
+ const secondId = asModelId("second-model");
274
+ const second = await openModel(secondId);
275
+ const response = new Deferred<null>();
276
+ mockSendModelValue.mockReturnValueOnce(response.promise);
277
+
278
+ const firstSend = first.send({ value: 1 });
279
+ await second.send({ value: 2 });
280
+ expect(
281
+ mockSendModelValue.mock.calls.map(([request]) => request.modelId),
282
+ ).toEqual([testId, secondId]);
283
+ response.resolve(null);
284
+ await firstSend;
285
+ });
286
+
287
+ it("drops queued messages when the model closes", async () => {
288
+ const model = await openModel();
289
+ const response = new Deferred<null>();
290
+ mockSendModelValue.mockReturnValueOnce(response.promise);
291
+ const first = model.send({ value: 1 });
292
+ model.set("count", 2);
293
+ model.save_changes();
294
+ const last = model.send({ value: 3 });
295
+
296
+ await vi.waitFor(() =>
297
+ expect(mockSendModelValue).toHaveBeenCalledTimes(1),
298
+ );
299
+ await handleWidgetMessage(registry, {
300
+ model_id: testId,
301
+ message: { method: "close" },
302
+ });
303
+ response.resolve(null);
304
+ await Promise.all([first, last]);
305
+ expect(mockSendModelValue).toHaveBeenCalledTimes(1);
306
+ });
307
+ });
308
+
158
309
  describe("static mode", () => {
159
310
  beforeEach(() => {
160
311
  mockIsStatic.mockReturnValue(true);
@@ -157,7 +157,9 @@ export class Model<T extends ModelState> implements AnyModel<T> {
157
157
 
158
158
  // Clear the dirty fields to avoid sending again.
159
159
  this.#dirtyFields.clear();
160
- this.#comm.sendUpdate(partialData);
160
+ this.#comm.sendUpdate(partialData).catch((error) => {
161
+ Logger.error("[anywidget] Failed to save model changes", error);
162
+ });
161
163
  }
162
164
 
163
165
  /**
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  import type { NotificationMessageData } from "@/core/kernel/messages";
3
3
  import { getRequestClient } from "@/core/network/requests";
4
+ import type { ModelRequest } from "@/core/network/types";
4
5
  import { isStaticNotebook } from "@/core/static/static-state";
5
6
  import { assertNever } from "@/utils/assertNever";
6
7
  import {
@@ -10,6 +11,7 @@ import {
10
11
  } from "@/utils/json/base64";
11
12
  import { Logger } from "@/utils/Logger";
12
13
  import { repl } from "@/utils/repl";
14
+ import { Semaphore } from "@/utils/semaphore";
13
15
  import { viewStateAtom } from "@/core/mode";
14
16
  import { store } from "@/core/state/jotai";
15
17
  import { createHost, type WidgetResolver } from "./host";
@@ -191,6 +193,20 @@ export async function handleWidgetMessage(
191
193
  }
192
194
 
193
195
  registry.createModel(modelId, (signal) => {
196
+ // Wait for the server to acknowledge queueing each message before
197
+ // sending the next one, preserving order within this model.
198
+ const sends = new Semaphore(1);
199
+ const sendMessage = (request: ModelRequest): Promise<void> =>
200
+ sends.run(async () => {
201
+ if (signal.aborted) {
202
+ Logger.debug(
203
+ `[Model] ${request.message.method} suppressed for model=${modelId} (signal aborted)`,
204
+ );
205
+ return;
206
+ }
207
+ await getRequestClient().sendModelValue(request);
208
+ });
209
+
194
210
  // In static exports there is no kernel, so comm calls are no-ops.
195
211
  const comm: MarimoComm<ModelState> = isStaticNotebook()
196
212
  ? {
@@ -199,28 +215,16 @@ export async function handleWidgetMessage(
199
215
  }
200
216
  : {
201
217
  async sendUpdate(changeData) {
202
- if (signal.aborted) {
203
- Logger.debug(
204
- `[Model] sendUpdate suppressed for model=${modelId} (signal aborted)`,
205
- );
206
- return;
207
- }
208
218
  const { state, buffers, bufferPaths } =
209
219
  serializeBuffersToBase64(changeData);
210
- await getRequestClient().sendModelValue({
220
+ await sendMessage({
211
221
  modelId,
212
222
  message: { method: "update", state, bufferPaths },
213
223
  buffers,
214
224
  });
215
225
  },
216
226
  async sendCustomMessage(content, buffers) {
217
- if (signal.aborted) {
218
- Logger.debug(
219
- `[Model] sendCustomMessage suppressed for model=${modelId} (signal aborted)`,
220
- );
221
- return;
222
- }
223
- await getRequestClient().sendModelValue({
227
+ await sendMessage({
224
228
  modelId,
225
229
  message: { method: "custom", content },
226
230
  buffers: buffers.map(dataViewToBase64),
@@ -93,6 +93,7 @@ describe("createReducer", () => {
93
93
  const loggerSpy = vi.spyOn(Logger, "error");
94
94
 
95
95
  const state = { count: 0 };
96
+ // @ts-expect-error - exercise runtime handling of an invalid action
96
97
  const newState = reducer(state, { type: "nonexistent", payload: null });
97
98
 
98
99
  expect(newState).toBe(state);
@@ -16,21 +16,27 @@ interface ReducerHandlers<State> {
16
16
  [k: string]: ReducerHandler<State, any>;
17
17
  }
18
18
 
19
- type ReducerActions<RH extends ReducerHandlers<any>> = {
20
- [Type in keyof RH]: RH[Type] extends ReducerHandler<any, infer Payload>
19
+ type ReducerActions<RH> = {
20
+ [Type in keyof RH]: RH[Type] extends (
21
+ state: never,
22
+ payload: infer Payload,
23
+ ) => unknown
21
24
  ? IfUnknown<Payload, () => void, (payload: Payload) => void>
22
25
  : never;
23
26
  };
24
27
 
25
28
  /** Helper for typing middleware that receives dispatched actions. */
26
29
  export type DispatchedActionOf<T> = {
27
- [Key in keyof T]: T[Key] extends (payload: infer P) => any
30
+ [Key in keyof T]: T[Key] extends (payload: infer P) => unknown
28
31
  ? { type: Key; payload: P }
29
32
  : never;
30
33
  }[keyof T & string];
31
34
 
32
35
  type ReducerActionOf<RH> = {
33
- [Type in keyof RH]: RH[Type] extends ReducerHandler<any, infer Payload>
36
+ [Type in keyof RH]: RH[Type] extends (
37
+ state: never,
38
+ payload: infer Payload,
39
+ ) => unknown
34
40
  ? { type: Type; payload: Payload }
35
41
  : never;
36
42
  }[keyof RH & string];
@@ -42,7 +48,7 @@ export interface ReducerCreatorResult<
42
48
  /**
43
49
  * The reducer function.
44
50
  */
45
- reducer: Reducer<State, any>;
51
+ reducer: Reducer<State, ReducerActionOf<RH>>;
46
52
  /**
47
53
  * Given a dispatch function, returns an object containing all the actions.
48
54
  */