Repository: facebook/react
Pull request: [Flight] Expose `encodeReply` from ReactFlightDOMClientEdge

Adds encodeReply to ReactFlightDOMClientEdge in webpack and turbopack bindings

Changed files:
filename: packages/react-server-dom-turbopack/src/ReactFlightDOMClientEdge.js
patch: @@ -11,6 +11,8 @@ import type {Thenable} from 'shared/ReactTypes.js';
 
 import type {Response as FlightResponse} from 'react-client/src/ReactFlightClient';
 
+import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient';
+
 import type {
   SSRModuleMap,
   ModuleLoading,
@@ -29,7 +31,10 @@ import {
   close,
 } from 'react-client/src/ReactFlightClient';
 
-import {createServerReference as createServerReferenceImpl} from 'react-client/src/ReactFlightReplyClient';
+import {
+  processReply,
+  createServerReference as createServerReferenceImpl,
+} from 'react-client/src/ReactFlightReplyClient';
 
 function noServerCall() {
   throw new Error(
@@ -112,4 +117,14 @@ function createFromFetch<T>(
   return getRoot(response);
 }
 
-export {createFromFetch, createFromReadableStream};
+function encodeReply(
+  value: ReactServerValue,
+): Promise<
+  string | URLSearchParams | FormData,
+> /* We don't use URLSearchParams yet but maybe */ {
+  return new Promise((resolve, reject) => {
+    processReply(value, '', resolve, reject);
+  });
+}
+
+export {createFromFetch, createFromReadableStream, encodeReply};

filename: packages/react-server-dom-turbopack/src/__tests__/ReactFlightDOMReplyEdge-test.js
patch: @@ -0,0 +1,48 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+// Polyfills for test environment
+global.ReadableStream =
+  require('web-streams-polyfill/ponyfill/es6').ReadableStream;
+global.TextEncoder = require('util').TextEncoder;
+global.TextDecoder = require('util').TextDecoder;
+
+// let serverExports;
+let turbopackServerMap;
+let ReactServerDOMServer;
+let ReactServerDOMClient;
+
+describe('ReactFlightDOMReply', () => {
+  beforeEach(() => {
+    jest.resetModules();
+    // Simulate the condition resolution
+    jest.mock('react', () => require('react/react.shared-subset'));
+    jest.mock('react-server-dom-turbopack/server', () =>
+      require('react-server-dom-turbopack/server.edge'),
+    );
+    const TurbopackMock = require('./utils/TurbopackMock');
+    // serverExports = TurbopackMock.serverExports;
+    turbopackServerMap = TurbopackMock.turbopackServerMap;
+    ReactServerDOMServer = require('react-server-dom-turbopack/server.edge');
+    jest.resetModules();
+    ReactServerDOMClient = require('react-server-dom-turbopack/client.edge');
+  });
+
+  it('can encode a reply', async () => {
+    const body = await ReactServerDOMClient.encodeReply({some: 'object'});
+    const decoded = await ReactServerDOMServer.decodeReply(
+      body,
+      turbopackServerMap,
+    );
+
+    expect(decoded).toEqual({some: 'object'});
+  });
+});

filename: packages/react-server-dom-webpack/src/ReactFlightDOMClientEdge.js
patch: @@ -11,6 +11,8 @@ import type {Thenable} from 'shared/ReactTypes.js';
 
 import type {Response as FlightResponse} from 'react-client/src/ReactFlightClient';
 
+import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient';
+
 import type {
   SSRModuleMap,
   ModuleLoading,
@@ -29,7 +31,10 @@ import {
   close,
 } from 'react-client/src/ReactFlightClient';
 
-import {createServerReference as createServerReferenceImpl} from 'react-client/src/ReactFlightReplyClient';
+import {
+  processReply,
+  createServerReference as createServerReferenceImpl,
+} from 'react-client/src/ReactFlightReplyClient';
 
 function noServerCall() {
   throw new Error(
@@ -112,4 +117,14 @@ function createFromFetch<T>(
   return getRoot(response);
 }
 
-export {createFromFetch, createFromReadableStream};
+function encodeReply(
+  value: ReactServerValue,
+): Promise<
+  string | URLSearchParams | FormData,
+> /* We don't use URLSearchParams yet but maybe */ {
+  return new Promise((resolve, reject) => {
+    processReply(value, '', resolve, reject);
+  });
+}
+
+export {createFromFetch, createFromReadableStream, encodeReply};

filename: packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReplyEdge-test.js
patch: @@ -0,0 +1,48 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+// Polyfills for test environment
+global.ReadableStream =
+  require('web-streams-polyfill/ponyfill/es6').ReadableStream;
+global.TextEncoder = require('util').TextEncoder;
+global.TextDecoder = require('util').TextDecoder;
+
+// let serverExports;
+let webpackServerMap;
+let ReactServerDOMServer;
+let ReactServerDOMClient;
+
+describe('ReactFlightDOMReplyEdge', () => {
+  beforeEach(() => {
+    jest.resetModules();
+    // Simulate the condition resolution
+    jest.mock('react', () => require('react/react.shared-subset'));
+    jest.mock('react-server-dom-webpack/server', () =>
+      require('react-server-dom-webpack/server.edge'),
+    );
+    const WebpackMock = require('./utils/WebpackMock');
+    // serverExports = WebpackMock.serverExports;
+    webpackServerMap = WebpackMock.webpackServerMap;
+    ReactServerDOMServer = require('react-server-dom-webpack/server.edge');
+    jest.resetModules();
+    ReactServerDOMClient = require('react-server-dom-webpack/client.edge');
+  });
+
+  it('can encode a reply', async () => {
+    const body = await ReactServerDOMClient.encodeReply({some: 'object'});
+    const decoded = await ReactServerDOMServer.decodeReply(
+      body,
+      webpackServerMap,
+    );
+
+    expect(decoded).toEqual({some: 'object'});
+  });
+});