From d8143bf8027ba5d1765e06f32e245c4683f51a2c Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Fri, 21 Feb 2025 16:53:15 +0100
Subject: [PATCH 01/16] React.promise

---
 src/React.res | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/React.res b/src/React.res
index 0beaa59..c738631 100644
--- a/src/React.res
+++ b/src/React.res
@@ -5,6 +5,7 @@ type element = Jsx.element
 external float: float => element = "%identity"
 external int: int => element = "%identity"
 external string: string => element = "%identity"
+external promise: promise<element> => element = "%identity"
 
 external array: array<element> => element = "%identity"
 

From 16b11dcdce4d22e753e4c0f612278622079f84a1 Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Fri, 21 Feb 2025 17:05:23 +0100
Subject: [PATCH 02/16] React.useTransition

---
 src/React.res | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/React.res b/src/React.res
index c738631..a18e8e5 100644
--- a/src/React.res
+++ b/src/React.res
@@ -312,9 +312,6 @@ external useImperativeHandle7: (
 
 @module("react") external useDeferredValue: 'value => 'value = "useDeferredValue"
 
-@module("react")
-external useTransition: unit => (bool, (unit => unit) => unit) = "useTransition"
-
 @module("react")
 external useInsertionEffectOnEveryRender: (unit => option<unit => unit>) => unit =
   "useInsertionEffect"
@@ -406,3 +403,13 @@ external setDisplayName: (component<'props>, string) => unit = "displayName"
 
 @get @return(nullable)
 external displayName: component<'props> => option<string> = "displayName"
+
+// Actions
+
+type transitionFunction = unit => promise<unit>
+
+type transitionStartFunction = transitionFunction => unit
+
+/** `useTransition` is a React Hook that lets you render a part of the UI in the background. */
+@module("react")
+external useTransition: unit => (bool, transitionStartFunction) = "useTransition"

From fddcca6997ee65b1cf44d8bff0af6e39def0bd59 Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Fri, 21 Feb 2025 17:20:51 +0100
Subject: [PATCH 03/16] React.useActionState

---
 src/React.res | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/React.res b/src/React.res
index a18e8e5..f64ca39 100644
--- a/src/React.res
+++ b/src/React.res
@@ -413,3 +413,15 @@ type transitionStartFunction = transitionFunction => unit
 /** `useTransition` is a React Hook that lets you render a part of the UI in the background. */
 @module("react")
 external useTransition: unit => (bool, transitionStartFunction) = "useTransition"
+
+type action<'state, 'payload> = ('state, 'payload) => promise<'state>
+
+type formAction<'formData> = 'formData => promise<unit>
+
+/** `useActionState` is a Hook that allows you to update state based on the result of a form action. */
+@module("react")
+external useActionState: (
+  action<'state, 'payload>,
+  'state,
+  ~permalink: string=?,
+) => ('state, formAction<'payload>, bool) = "useActionState"

From 0f0466571b4632b6a8cba798aab05715202c5656 Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Fri, 21 Feb 2025 17:27:58 +0100
Subject: [PATCH 04/16] React.useOptimistic

---
 src/React.res | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/React.res b/src/React.res
index f64ca39..b6b0a79 100644
--- a/src/React.res
+++ b/src/React.res
@@ -425,3 +425,8 @@ external useActionState: (
   'state,
   ~permalink: string=?,
 ) => ('state, formAction<'payload>, bool) = "useActionState"
+
+/** `useOptimistic` is a React Hook that lets you optimistically update the UI. */
+@module("react")
+external useOptimistic: ('state, ('state, 'action) => 'state) => ('state, 'action => unit) =
+  "useOptimistic"

From 235bfd0773af63d863d7af7aa78dff22d9b89627 Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Fri, 21 Feb 2025 17:36:48 +0100
Subject: [PATCH 05/16] React.use

---
 src/React.res | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/React.res b/src/React.res
index b6b0a79..68527ae 100644
--- a/src/React.res
+++ b/src/React.res
@@ -430,3 +430,14 @@ external useActionState: (
 @module("react")
 external useOptimistic: ('state, ('state, 'action) => 'state) => ('state, 'action => unit) =
   "useOptimistic"
+
+module Usable = {
+  type t<'value>
+
+  external context: Context.t<'value> => t<'value> = "%identity"
+  external promise: promise<'value> => t<'value> = "%identity"
+}
+
+/** `use` is a React API that lets you read the value of a resource like a Promise or context. */
+@module("react")
+external use: Usable.t<'value> => 'value = "use"

From dd90512a792d2a2bd77cdafead166c2556bf8964 Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Sun, 27 Apr 2025 17:43:43 +0200
Subject: [PATCH 06/16] React.act

---
 src/React.res | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/React.res b/src/React.res
index 68527ae..960007a 100644
--- a/src/React.res
+++ b/src/React.res
@@ -441,3 +441,7 @@ module Usable = {
 /** `use` is a React API that lets you read the value of a resource like a Promise or context. */
 @module("react")
 external use: Usable.t<'value> => 'value = "use"
+
+/** `act` is a test helper to apply pending React updates before making assertions. */
+@module("react")
+external act: (unit => promise<unit>) => promise<unit> = "act"

From 34422a1e81e4fee96d92427aa15d336d7a8923c4 Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Sun, 13 Apr 2025 14:45:23 +0200
Subject: [PATCH 07/16] React.useDeferredValue now takes initial value

---
 src/React.res | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/React.res b/src/React.res
index 960007a..9c5e997 100644
--- a/src/React.res
+++ b/src/React.res
@@ -310,7 +310,9 @@ external useImperativeHandle7: (
 
 @module("react") external useId: unit => string = "useId"
 
-@module("react") external useDeferredValue: 'value => 'value = "useDeferredValue"
+/** `useDeferredValue` is a React Hook that lets you defer updating a part of the UI. */
+@module("react")
+external useDeferredValue: ('value, ~initialValue: 'value=?) => 'value = "useDeferredValue"
 
 @module("react")
 external useInsertionEffectOnEveryRender: (unit => option<unit => unit>) => unit =

From d742924422bc63bb1681603b40466c807b672eb5 Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Fri, 21 Feb 2025 17:36:58 +0100
Subject: [PATCH 08/16] ReactDOM: ref cleanup function

---
 src/ReactDOM.res | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/ReactDOM.res b/src/ReactDOM.res
index 04c39c2..4206e74 100644
--- a/src/ReactDOM.res
+++ b/src/ReactDOM.res
@@ -37,7 +37,7 @@ type domRef = JsxDOM.domRef
 module Ref = {
   type t = domRef
   type currentDomRef = React.ref<Js.nullable<Dom.element>>
-  type callbackDomRef = Js.nullable<Dom.element> => unit
+  type callbackDomRef = Js.nullable<Dom.element> => option<unit => unit>
 
   external domRef: currentDomRef => domRef = "%identity"
   external callbackDomRef: callbackDomRef => domRef = "%identity"

From f74a62d866a4e55f6b8fa48388a5bca851762672 Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Sun, 27 Apr 2025 17:05:42 +0200
Subject: [PATCH 09/16] ReactDOM: Resource Preloading APIse

---
 src/ReactDOM.res | 111 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

diff --git a/src/ReactDOM.res b/src/ReactDOM.res
index 4206e74..3ef3900 100644
--- a/src/ReactDOM.res
+++ b/src/ReactDOM.res
@@ -43,6 +43,117 @@ module Ref = {
   external callbackDomRef: callbackDomRef => domRef = "%identity"
 }
 
+// Resource Preloading APIs
+
+/** The CORS policy to use. */
+type crossOrigin = [
+  | #anonymous
+  | #"use-credentials"
+]
+
+/** The Referrer header to send when fetching. */
+type referrerPolicy = [
+  | #"referrer-when-downgrade"
+  | #"no-referrer"
+  | #origin
+  | #"origin-when-cross-origin"
+  | #"unsafe-url"
+]
+
+/** Suggests a relative priority for fetching the resource. */
+type fetchPriority = [#auto | #high | #low]
+
+/** `prefetchDNS` lets you eagerly look up the IP of a server that you expect to load resources from. */
+@module("react-dom")
+external prefetchDNS: string => unit = "prefetchDNS"
+
+/** `preconnect` lets you eagerly connect to a server that you expect to load resources from. */
+@module("react-dom")
+external preconnect: string => unit = "preconnect"
+
+type preloadOptions = {
+  /** The type of resource. */
+  @as("as")
+  as_: [
+    | #audio
+    | #document
+    | #embed
+    | #fetch
+    | #font
+    | #image
+    | #object
+    | #script
+    | #style
+    | #track
+    | #video
+    | #worker
+  ],
+  /** The CORS policy to use. It is required when as is set to "fetch". */
+  crossOrigin?: crossOrigin,
+  /** The Referrer header to send when fetching. */
+  referrerPolicy?: referrerPolicy,
+  /** A cryptographic hash of the resource, to verify its authenticity. */
+  integrity?: string,
+  /** The MIME type of the resource. */
+  @as("type")
+  type_?: string,
+  /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */
+  nonce?: string,
+  /** Suggests a relative priority for fetching the resource. */
+  fetchPriority?: fetchPriority,
+  /** For use only with as: "image". Specifies the source set of the image. */
+  imageSrcSet?: string,
+  /** For use only with as: "image". Specifies the sizes of the image. */
+  imageSizes?: string,
+}
+
+/** `preload` lets you eagerly fetch a resource such as a stylesheet, font, or external script that you expect to use. */
+@module("react-dom")
+external preload: (string, preloadOptions) => unit = "preload"
+
+type preloadModuleOptions = {
+  /** The type of resource. */
+  @as("as")
+  as_: [#script],
+  /** The CORS policy to use. It is required when as is set to "fetch". */
+  crossOrigin?: crossOrigin,
+  /** A cryptographic hash of the resource, to verify its authenticity. */
+  integrity?: string,
+  /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */
+  nonce?: string,
+}
+
+/** `preloadModule` lets you eagerly fetch an ESM module that you expect to use. */
+@module("react-dom")
+external preloadModule: (string, preloadModuleOptions) => unit = "preloadModule"
+
+type preinitOptions = {
+  /** The type of resource. */
+  @as("as")
+  as_: [#script | #style],
+  /** Required with stylesheets. Says where to insert the stylesheet relative to others. Stylesheets with higher precedence can override those with lower precedence. */
+  precedence?: [#reset | #low | #medium | #high],
+  /** The CORS policy to use. It is required when as is set to "fetch". */
+  crossOrigin?: crossOrigin,
+  /** The Referrer header to send when fetching. */
+  referrerPolicy?: referrerPolicy,
+  /** A cryptographic hash of the resource, to verify its authenticity. */
+  integrity?: string,
+  nonce?: string,
+  /** Suggests a relative priority for fetching the resource. */
+  fetchPriority?: fetchPriority,
+}
+
+/** `preinit` lets you eagerly fetch and evaluate a stylesheet or external script. */
+@module("react-dom")
+external preinit: (string, preinitOptions) => unit = "preinit"
+
+/** To preinit an ESM module, call the `preinitModule` function from react-dom. */
+@module("react-dom")
+external preinitModule: (string, preloadModuleOptions) => unit = "preinitModule"
+
+// Runtime
+
 type domProps = JsxDOM.domProps
 
 @variadic @module("react")

From af4bddb0c87c3f8bebb78bf0d92ca751fecbd92b Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Fri, 21 Feb 2025 17:28:18 +0100
Subject: [PATCH 10/16] ReactDOM.useFormStatus

---
 src/ReactDOM.res | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/src/ReactDOM.res b/src/ReactDOM.res
index 3ef3900..fc226f3 100644
--- a/src/ReactDOM.res
+++ b/src/ReactDOM.res
@@ -25,6 +25,23 @@ module Client = {
   external hydrateRoot: (Dom.element, React.element) => Root.t = "hydrateRoot"
 }
 
+// Very rudimentary form data bindings
+module FormData = {
+  type t
+  type value
+
+  @new external make: unit => t = "FormData"
+
+  @send external append: (t, string, ~filename: string=?) => unit = "append"
+  @send external delete: (t, string) => unit = "delete"
+  @send external get: (t, string) => option<value> = "get"
+  @send external getAll: (t, string) => array<value> = "getAll"
+  @send external set: (string, string) => unit = "set"
+  @send external has: string => bool = "has"
+  // @send external keys: t => Iterator.t<string> = "keys";
+  // @send external values: t => Iterator.t<value> = "values";
+}
+
 @module("react-dom")
 external createPortal: (React.element, Dom.element) => React.element = "createPortal"
 
@@ -43,6 +60,23 @@ module Ref = {
   external callbackDomRef: callbackDomRef => domRef = "%identity"
 }
 
+// Hooks
+
+type formStatus<'state> = {
+  /** If true, this means the parent <form> is pending submission. Otherwise, false. */
+  pending: bool,
+  /** An object implementing the FormData interface that contains the data the parent <form> is submitting. If there is no active submission or no parent <form>, it will be null. */
+  data: FormData.t,
+  /** This represents whether the parent <form> is submitting with either a GET or POST HTTP method. By default, a <form> will use the GET method and can be specified by the method property. */
+  method: [#get | #post],
+  /** A reference to the function passed to the action prop on the parent <form>. If there is no parent <form>, the property is null. If there is a URI value provided to the action prop, or no action prop specified, status.action will be null. */
+  action: React.action<'state, FormData.t>,
+}
+
+/** `useFormStatus` is a Hook that gives you status information of the last form submission. */
+@module("react-dom")
+external useFormStatus: unit => formStatus<'state> = "useFormStatus"
+
 // Resource Preloading APIs
 
 /** The CORS policy to use. */

From c99755c82b9d78dcebb47e9c7e242c5a4ec00788 Mon Sep 17 00:00:00 2001
From: Christoph Knittel <ck@cca.io>
Date: Sun, 27 Apr 2025 18:06:05 +0200
Subject: [PATCH 11/16] JS output changes

---
 src/React.bs.js    | 6 +++---
 src/ReactDOM.bs.js | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/React.bs.js b/src/React.bs.js
index c2471b6..3eb8131 100644
--- a/src/React.bs.js
+++ b/src/React.bs.js
@@ -3,8 +3,6 @@
 
 var React = require("react");
 
-var Ref = {};
-
 var Children = {};
 
 var Context = {};
@@ -25,7 +23,8 @@ function lazy_(load) {
 
 var Uncurried = {};
 
-exports.Ref = Ref;
+var Usable = {};
+
 exports.Children = Children;
 exports.Context = Context;
 exports.Fragment = Fragment;
@@ -33,4 +32,5 @@ exports.StrictMode = StrictMode;
 exports.Suspense = Suspense;
 exports.lazy_ = lazy_;
 exports.Uncurried = Uncurried;
+exports.Usable = Usable;
 /* react Not a pure module */
diff --git a/src/ReactDOM.bs.js b/src/ReactDOM.bs.js
index b65084d..06f42ca 100644
--- a/src/ReactDOM.bs.js
+++ b/src/ReactDOM.bs.js
@@ -8,14 +8,14 @@ var Client = {
   Root: Root
 };
 
-var Ref = {};
+var $$FormData = {};
 
-var Props = {};
+var Ref = {};
 
 var Style;
 
 exports.Client = Client;
+exports.$$FormData = $$FormData;
 exports.Ref = Ref;
-exports.Props = Props;
 exports.Style = Style;
 /* No side effect */

From 3a539345ad3fa265030e7d01ed63c34fcd2bb98a Mon Sep 17 00:00:00 2001
From: Matthias Le Brun <bloodyowl@icloud.com>
Date: Sat, 3 May 2025 14:38:39 +0200
Subject: [PATCH 12/16] Add external for basic support for formAction

---
 src/ReactDOM.res | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/ReactDOM.res b/src/ReactDOM.res
index fc226f3..160bb55 100644
--- a/src/ReactDOM.res
+++ b/src/ReactDOM.res
@@ -73,6 +73,8 @@ type formStatus<'state> = {
   action: React.action<'state, FormData.t>,
 }
 
+external formAction: React.formAction<FormData.t> => string = "%identity"
+
 /** `useFormStatus` is a Hook that gives you status information of the last form submission. */
 @module("react-dom")
 external useFormStatus: unit => formStatus<'state> = "useFormStatus"

From 1694f228fdcee4bdf57ec05111ea6a857aa6e33d Mon Sep 17 00:00:00 2001
From: Matthias Le Brun <bloodyowl@icloud.com>
Date: Sat, 3 May 2025 15:35:52 +0200
Subject: [PATCH 13/16] Add `usePromise` for `use(promise)`

`use(context)` seems to exactly replicate the `useContext(context)`
logic, and we want to maximize retro-compability (ie. not switch from
`useContext` to `use` for that under the hood).

simply adding `usePromise(promise)` seems to be the simplest, least
invasive way to add the functionality.
---
 src/React.bs.js |  3 ---
 src/React.res   | 14 +++-----------
 2 files changed, 3 insertions(+), 14 deletions(-)

diff --git a/src/React.bs.js b/src/React.bs.js
index 3eb8131..ef827dd 100644
--- a/src/React.bs.js
+++ b/src/React.bs.js
@@ -23,8 +23,6 @@ function lazy_(load) {
 
 var Uncurried = {};
 
-var Usable = {};
-
 exports.Children = Children;
 exports.Context = Context;
 exports.Fragment = Fragment;
@@ -32,5 +30,4 @@ exports.StrictMode = StrictMode;
 exports.Suspense = Suspense;
 exports.lazy_ = lazy_;
 exports.Uncurried = Uncurried;
-exports.Usable = Usable;
 /* react Not a pure module */
diff --git a/src/React.res b/src/React.res
index 9c5e997..0ab5809 100644
--- a/src/React.res
+++ b/src/React.res
@@ -251,6 +251,9 @@ external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback =
 @module("react")
 external useContext: Context.t<'any> => 'any = "useContext"
 
+@module("react")
+external usePromise: promise<'a> => 'a = "use"
+
 @module("react") external useRef: 'value => ref<'value> = "useRef"
 
 @module("react")
@@ -433,17 +436,6 @@ external useActionState: (
 external useOptimistic: ('state, ('state, 'action) => 'state) => ('state, 'action => unit) =
   "useOptimistic"
 
-module Usable = {
-  type t<'value>
-
-  external context: Context.t<'value> => t<'value> = "%identity"
-  external promise: promise<'value> => t<'value> = "%identity"
-}
-
-/** `use` is a React API that lets you read the value of a resource like a Promise or context. */
-@module("react")
-external use: Usable.t<'value> => 'value = "use"
-
 /** `act` is a test helper to apply pending React updates before making assertions. */
 @module("react")
 external act: (unit => promise<unit>) => promise<unit> = "act"

From 1106232379000b1a73e3351986d7bee0c14870e0 Mon Sep 17 00:00:00 2001
From: Matthias Le Brun <bloodyowl@icloud.com>
Date: Sat, 3 May 2025 16:26:47 +0200
Subject: [PATCH 14/16] proposal: make FormData more usable to get values

this **kinda** goes against the zero-cost philosophy, but I don't see a
world where users would not have to reimplement those.
---
 src/ReactDOM.bs.js | 39 ++++++++++++++++++++++++++++++++++++++-
 src/ReactDOM.res   | 35 ++++++++++++++++++++++++++++++++---
 2 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/src/ReactDOM.bs.js b/src/ReactDOM.bs.js
index 06f42ca..fa51640 100644
--- a/src/ReactDOM.bs.js
+++ b/src/ReactDOM.bs.js
@@ -1,6 +1,7 @@
 // Generated by ReScript, PLEASE EDIT WITH CARE
 'use strict';
 
+var Caml_option = require("rescript/lib/js/caml_option.js");
 
 var Root = {};
 
@@ -8,7 +9,43 @@ var Client = {
   Root: Root
 };
 
-var $$FormData = {};
+function getString(formData, name) {
+  var value = formData.get(name);
+  if (!(value == null) && typeof value === "string") {
+    return Caml_option.some(value);
+  }
+  
+}
+
+function getFile(formData, name) {
+  var value = formData.get(name);
+  if (!(value == null) && typeof value !== "string") {
+    return Caml_option.some(value);
+  }
+  
+}
+
+function getAll(t, string) {
+  return t.getAll(string).map(function (value) {
+              if (typeof value === "string") {
+                return {
+                        TAG: "String",
+                        _0: value
+                      };
+              } else {
+                return {
+                        TAG: "File",
+                        _0: value
+                      };
+              }
+            });
+}
+
+var $$FormData = {
+  getString: getString,
+  getFile: getFile,
+  getAll: getAll
+};
 
 var Ref = {};
 
diff --git a/src/ReactDOM.res b/src/ReactDOM.res
index 160bb55..fbd564b 100644
--- a/src/ReactDOM.res
+++ b/src/ReactDOM.res
@@ -28,14 +28,43 @@ module Client = {
 // Very rudimentary form data bindings
 module FormData = {
   type t
-  type value
+  type file
+
+  type formValue =
+    | String(string)
+    | File(file)
 
   @new external make: unit => t = "FormData"
 
   @send external append: (t, string, ~filename: string=?) => unit = "append"
   @send external delete: (t, string) => unit = "delete"
-  @send external get: (t, string) => option<value> = "get"
-  @send external getAll: (t, string) => array<value> = "getAll"
+  @return(nullable) @send external getUnsafe: (t, string) => option<'a> = "get"
+  @send external getAllUnsafe: (t, string) => array<'a> = "getAll"
+
+  let getString = (formData, name) => {
+    switch formData->getUnsafe(name) {
+    | Some(value) => Js.typeof(value) === "string" ? Some(value) : None
+    | _ => None
+    }
+  }
+
+  external _asFile: 'a => file = "%identity"
+
+  let getFile = (formData, name) => {
+    switch formData->getUnsafe(name) {
+    | Some(value) => Js.typeof(value) === "string" ? None : Some(value->_asFile)
+    | _ => None
+    }
+  }
+
+  let getAll = (t, string) => {
+    t
+    ->getAllUnsafe(string)
+    ->Js.Array2.map(value => {
+      Js.typeof(value) === "string" ? String(value) : File(value->_asFile)
+    })
+  }
+
   @send external set: (string, string) => unit = "set"
   @send external has: string => bool = "has"
   // @send external keys: t => Iterator.t<string> = "keys";

From 5a5916153b44a0b7db484be34a4965182df7e84c Mon Sep 17 00:00:00 2001
From: Freddy Harris <freddy03h@gmail.com>
Date: Sun, 4 May 2025 10:11:54 +0200
Subject: [PATCH 15/16] useOptimistic optionnal updateFn

---
 src/React.res | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/React.res b/src/React.res
index 0ab5809..f1f6831 100644
--- a/src/React.res
+++ b/src/React.res
@@ -433,8 +433,10 @@ external useActionState: (
 
 /** `useOptimistic` is a React Hook that lets you optimistically update the UI. */
 @module("react")
-external useOptimistic: ('state, ('state, 'action) => 'state) => ('state, 'action => unit) =
-  "useOptimistic"
+external useOptimistic: (
+  'state,
+  ~updateFn: ('state, 'action) => 'state=?,
+) => ('state, 'action => unit) = "useOptimistic"
 
 /** `act` is a test helper to apply pending React updates before making assertions. */
 @module("react")

From ca5ce8f66f1ea7596410add3eb1f5b06eaff0b6e Mon Sep 17 00:00:00 2001
From: Freddy Harris <freddy03h@gmail.com>
Date: Sun, 4 May 2025 11:34:56 +0200
Subject: [PATCH 16/16] dom static prerender and prerenderToNodeStream

---
 src/ReactDOMStatic.bs.js |  2 ++
 src/ReactDOMStatic.res   | 30 ++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)
 create mode 100644 src/ReactDOMStatic.bs.js
 create mode 100644 src/ReactDOMStatic.res

diff --git a/src/ReactDOMStatic.bs.js b/src/ReactDOMStatic.bs.js
new file mode 100644
index 0000000..d856702
--- /dev/null
+++ b/src/ReactDOMStatic.bs.js
@@ -0,0 +1,2 @@
+// Generated by ReScript, PLEASE EDIT WITH CARE
+/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
diff --git a/src/ReactDOMStatic.res b/src/ReactDOMStatic.res
new file mode 100644
index 0000000..7988fbb
--- /dev/null
+++ b/src/ReactDOMStatic.res
@@ -0,0 +1,30 @@
+type abortSignal // WebAPI.EventAPI.abortSignal
+
+type nodeStream // NodeJs.Stream.stream
+
+type readableStream // WebAPI.FileAPI.readableStream
+
+type prerenderOptions<'error> = {
+  bootstrapScriptContent?: string,
+  bootstrapScripts?: array<string>,
+  bootstrapModules?: array<string>,
+  identifierPrefix?: string,
+  namespaceURI?: string,
+  onError?: 'error => unit,
+  progressiveChunkSize?: int,
+  signal?: abortSignal,
+}
+
+type staticResult = {prelude: readableStream}
+
+@module("react-dom/static")
+external prerender: (React.element, ~options: prerenderOptions<'error>=?) => promise<staticResult> =
+  "prerender"
+
+type staticResultNode = {prelude: nodeStream}
+
+@module("react-dom/static")
+external prerenderToNodeStream: (
+  React.element,
+  ~options: prerenderOptions<'error>=?,
+) => promise<staticResultNode> = "prerenderToNodeStream"