From d8143bf8027ba5d1765e06f32e245c4683f51a2c Mon Sep 17 00:00:00 2001 From: Christoph Knittel 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 = "%identity" external array: array => element = "%identity" From 16b11dcdce4d22e753e4c0f612278622079f84a1 Mon Sep 17 00:00:00 2001 From: Christoph Knittel 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 = "useInsertionEffect" @@ -406,3 +403,13 @@ external setDisplayName: (component<'props>, string) => unit = "displayName" @get @return(nullable) external displayName: component<'props> => option = "displayName" + +// Actions + +type transitionFunction = unit => promise + +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 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 + +/** `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 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 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 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) => promise = "act" From 34422a1e81e4fee96d92427aa15d336d7a8923c4 Mon Sep 17 00:00:00 2001 From: Christoph Knittel 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 = From d742924422bc63bb1681603b40466c807b672eb5 Mon Sep 17 00:00:00 2001 From: Christoph Knittel 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> - type callbackDomRef = Js.nullable => unit + type callbackDomRef = Js.nullable => option unit> external domRef: currentDomRef => domRef = "%identity" external callbackDomRef: callbackDomRef => domRef = "%identity" From f74a62d866a4e55f6b8fa48388a5bca851762672 Mon Sep 17 00:00:00 2001 From: Christoph Knittel 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 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 = "get" + @send external getAll: (t, string) => array = "getAll" + @send external set: (string, string) => unit = "set" + @send external has: string => bool = "has" + // @send external keys: t => Iterator.t = "keys"; + // @send external values: t => Iterator.t = "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
is pending submission. Otherwise, false. */ + pending: bool, + /** An object implementing the FormData interface that contains the data the parent is submitting. If there is no active submission or no parent , it will be null. */ + data: FormData.t, + /** This represents whether the parent is submitting with either a GET or POST HTTP method. By default, a 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 . If there is no parent , 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 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 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 => 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 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) => promise = "act" From 1106232379000b1a73e3351986d7bee0c14870e0 Mon Sep 17 00:00:00 2001 From: Matthias Le Brun 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 = "get" - @send external getAll: (t, string) => array = "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 = "keys"; From 5a5916153b44a0b7db484be34a4965182df7e84c Mon Sep 17 00:00:00 2001 From: Freddy Harris 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 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, + bootstrapModules?: array, + 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 = + "prerender" + +type staticResultNode = {prelude: nodeStream} + +@module("react-dom/static") +external prerenderToNodeStream: ( + React.element, + ~options: prerenderOptions<'error>=?, +) => promise = "prerenderToNodeStream" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy