@samitouri / QOS-React-1 / commits / b9be4537c2

[Flight] provide property descriptors for client references (#27328)

Client reference proxy should implement getOwnPropertyDescriptor. One practical place where this shows up is when consuming CJS module.exports in ESM modules. Node creates named exports it statically infers from the underlying source but it only sets the named export if the CJS exports hasOwnProperty. This trap will allow the proxy to respond affirmatively. I did not add unit tests because contriving the ESM <-> CJS scenario in Jest is challenging. I did add new components to the flight fixture which demonstrate that the named exports are properly constructed with the client reference whereas they were not before.

Josh Story committed Sep 5, 2023 at 13:45 UTC b9be4537c2459f8fc0312b796570003620bc8600
6 files changed +213 -127
fixtures/flight/src/App.js
+9
@@ -10,6 +10,10 @@ const Counter3 = await(AsyncModule);
10 import ShowMore from './ShowMore.js';
11 import Button from './Button.js';
12 import Form from './Form.js';
13 +import {Dynamic} from './Dynamic.js';
14 +import {Client} from './Client.js';
15 +
16 +import {Note} from './cjs/Note.js';
17
18 import {like, greet} from './actions.js';
19
@@ -43,6 +47,11 @@ export default async function App() {
47 <div>
48 <Button action={like}>Like</Button>
49 </div>
50 + <div>
51 + loaded statically: <Dynamic />
52 + </div>
53 + <Client />
54 + <Note />
55 </Container>
56 </body>
57 </html>
fixtures/flight/src/Client.js new
+21
@@ -0,0 +1,21 @@
1 +'use client';
2 +
3 +import * as React from 'react';
4 +
5 +let LazyDynamic = React.lazy(() =>
6 + import('./Dynamic.js').then(exp => ({default: exp.Dynamic}))
7 +);
8 +
9 +export function Client() {
10 + const [loaded, load] = React.useReducer(() => true, false);
11 +
12 + return loaded ? (
13 + <div>
14 + loaded dynamically: <LazyDynamic />
15 + </div>
16 + ) : (
17 + <div>
18 + <button onClick={load}>Load dynamic import Component</button>
19 + </div>
20 + );
21 +}
fixtures/flight/src/Dynamic.js new
+12
@@ -0,0 +1,12 @@
1 +'use client';
2 +
3 +import * as React from 'react';
4 +
5 +export function Dynamic() {
6 + return (
7 + <div>
8 + This client component should be loaded in a single chunk even when it is
9 + used as both a client reference and as a dynamic import.
10 + </div>
11 + );
12 +}
fixtures/flight/src/cjs/Note.js new
+11
@@ -0,0 +1,11 @@
1 +'use client';
2 +
3 +var React = require('react');
4 +
5 +function Note() {
6 + return 'This component was exported on a commonJS module and imported into ESM as a named import.';
7 +}
8 +
9 +module.exports = {
10 + Note,
11 +};
fixtures/flight/yarn.lock
+48 -35
@@ -2690,17 +2690,17 @@
2690 fastq "^1.6.0"
2691
2692 "@pmmmwh/react-refresh-webpack-plugin@^0.5.3":
2693 - version "0.5.7"
2694 - resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.7.tgz#58f8217ba70069cc6a73f5d7e05e85b458c150e2"
2695 - integrity sha512-bcKCAzF0DV2IIROp9ZHkRJa6O4jy7NlnHdWL3GmcUxYWNjLXkK5kfELELwEfSP5hXPfVL/qOGMAROuMQb9GG8Q==
2693 + version "0.5.11"
2694 + resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz#7c2268cedaa0644d677e8c4f377bc8fb304f714a"
2695 + integrity sha512-7j/6vdTym0+qZ6u4XbSAxrWBGYSdCfTzySkj7WAFgDLmSyWlOrWvpyzxlFh5jtw9dn0oL/jtW+06XfFiisN3JQ==
2696 dependencies:
2697 ansi-html-community "^0.0.8"
2698 common-path-prefix "^3.0.0"
2699 - core-js-pure "^3.8.1"
2699 + core-js-pure "^3.23.3"
2700 error-stack-parser "^2.0.6"
2701 find-up "^5.0.0"
2702 html-entities "^2.1.0"
2703 - loader-utils "^2.0.0"
2703 + loader-utils "^2.0.4"
2704 schema-utils "^3.0.0"
2705 source-map "^0.7.3"
2706
@@ -3002,7 +3002,7 @@
3002 expect "^28.0.0"
3003 pretty-format "^28.0.0"
3004
3005 -"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6":
3005 +"@types/json-schema@*", "@types/json-schema@^7.0.5":
3006 version "7.0.6"
3007 resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
3008 integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
@@ -4050,10 +4050,10 @@ core-js-compat@^3.30.1, core-js-compat@^3.30.2:
4050 dependencies:
4051 browserslist "^4.21.5"
4052
4053 -core-js-pure@^3.8.1:
4054 - version "3.24.1"
4055 - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.24.1.tgz#8839dde5da545521bf282feb7dc6d0b425f39fd3"
4056 - integrity sha512-r1nJk41QLLPyozHUUPmILCEMtMw24NG4oWK6RbsDdjzQgg9ZvrUsPBj1MnG0wXXp1DCDU6j+wUvEmBSrtRbLXg==
4053 +core-js-pure@^3.23.3:
4054 + version "3.32.1"
4055 + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.32.1.tgz#5775b88f9062885f67b6d7edce59984e89d276f3"
4056 + integrity sha512-f52QZwkFVDPf7UEQZGHKx6NYxsxmVGJe5DIvbzOdRMJlmT6yv0KDjR8rmy3ngr/t5wU54c7Sp/qIJH0ppbhVpQ==
4057
4058 cosmiconfig@^6.0.0:
4059 version "6.0.0"
@@ -4582,11 +4582,11 @@ error-ex@^1.3.1:
4582 is-arrayish "^0.2.1"
4583
4584 error-stack-parser@^2.0.6:
4585 - version "2.0.6"
4586 - resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.6.tgz#5a99a707bd7a4c58a797902d48d82803ede6aad8"
4587 - integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==
4585 + version "2.1.4"
4586 + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286"
4587 + integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==
4588 dependencies:
4589 - stackframe "^1.1.1"
4589 + stackframe "^1.3.4"
4590
4591 es-abstract@^1.12.0:
4592 version "1.16.0"
@@ -4751,8 +4751,9 @@ fast-glob@^3.2.11, fast-glob@^3.2.9:
4751 micromatch "^4.0.4"
4752
4753 fast-json-stable-stringify@^2.0.0:
4754 - version "2.0.0"
4755 - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
4754 + version "2.1.0"
4755 + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
4756 + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
4757
4758 fast-levenshtein@~2.0.4:
4759 version "2.0.6"
@@ -5074,9 +5075,9 @@ html-encoding-sniffer@^2.0.1:
5075 whatwg-encoding "^1.0.5"
5076
5077 html-entities@^2.1.0:
5077 - version "2.3.3"
5078 - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46"
5079 - integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==
5078 + version "2.4.0"
5079 + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.4.0.tgz#edd0cee70402584c8c76cc2c0556db09d1f45061"
5080 + integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==
5081
5082 html-escaper@^2.0.0:
5083 version "2.0.2"
@@ -5958,17 +5959,23 @@ json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
5959 json-schema-traverse@^0.4.1:
5960 version "0.4.1"
5961 resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
5962 + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
5963
5964 json-schema-traverse@^1.0.0:
5965 version "1.0.0"
5966 resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
5967 integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
5968
5967 -json5@^2.1.0, json5@^2.1.2, json5@^2.2.1:
5969 +json5@^2.1.0, json5@^2.2.1:
5970 version "2.2.1"
5971 resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
5972 integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
5973
5974 +json5@^2.1.2:
5975 + version "2.2.3"
5976 + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
5977 + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
5978 +
5979 jsonfile@^6.0.1:
5980 version "6.1.0"
5981 resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
@@ -6017,7 +6024,7 @@ loader-runner@^4.2.0:
6024 resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
6025 integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
6026
6020 -loader-utils@^2.0.0:
6027 +loader-utils@^2.0.0, loader-utils@^2.0.4:
6028 version "2.0.4"
6029 resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c"
6030 integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==
@@ -7260,7 +7267,12 @@ pstree.remy@^1.1.8:
7267 resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
7268 integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
7269
7263 -punycode@^2.1.0, punycode@^2.1.1:
7270 +punycode@^2.1.0:
7271 + version "2.3.0"
7272 + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
7273 + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
7274 +
7275 +punycode@^2.1.1:
7276 version "2.1.1"
7277 resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
7278
@@ -7688,11 +7700,11 @@ schema-utils@^2.6.5:
7700 ajv-keywords "^3.5.2"
7701
7702 schema-utils@^3.0.0:
7691 - version "3.0.0"
7692 - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef"
7693 - integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==
7703 + version "3.3.0"
7704 + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
7705 + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
7706 dependencies:
7695 - "@types/json-schema" "^7.0.6"
7707 + "@types/json-schema" "^7.0.8"
7708 ajv "^6.12.5"
7709 ajv-keywords "^3.5.2"
7710
@@ -7862,9 +7874,9 @@ source-map@^0.5.0:
7874 resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
7875
7876 source-map@^0.7.3:
7865 - version "0.7.3"
7866 - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
7867 - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
7877 + version "0.7.4"
7878 + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
7879 + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
7880
7881 spawn-command@^0.0.2-1:
7882 version "0.0.2-1"
@@ -7886,10 +7898,10 @@ stack-utils@^2.0.3:
7898 dependencies:
7899 escape-string-regexp "^2.0.0"
7900
7889 -stackframe@^1.1.1:
7890 - version "1.2.0"
7891 - resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.0.tgz#52429492d63c62eb989804c11552e3d22e779303"
7892 - integrity sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==
7901 +stackframe@^1.3.4:
7902 + version "1.3.4"
7903 + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310"
7904 + integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==
7905
7906 statuses@2.0.1:
7907 version "2.0.1"
@@ -8379,8 +8391,9 @@ update-browserslist-db@^1.0.5:
8391 picocolors "^1.0.0"
8392
8393 uri-js@^4.2.2:
8382 - version "4.2.2"
8383 - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
8394 + version "4.4.1"
8395 + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
8396 + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
8397 dependencies:
8398 punycode "^2.1.0"
8399
packages/react-server-dom-webpack/src/ReactFlightWebpackReferences.js
+112 -92
@@ -134,105 +134,125 @@ const deepProxyHandlers = {
134 },
135 };
136
137 -const proxyHandlers = {
138 - get: function (
139 - target: Function,
140 - name: string,
141 - receiver: Proxy<Function>,
142 - ): $FlowFixMe {
143 - switch (name) {
144 - // These names are read by the Flight runtime if you end up using the exports object.
145 - case '$$typeof':
146 - return target.$$typeof;
147 - case '$$id':
148 - return target.$$id;
149 - case '$$async':
150 - return target.$$async;
151 - case 'name':
152 - return target.name;
153 - // We need to special case this because createElement reads it if we pass this
154 - // reference.
155 - case 'defaultProps':
156 - return undefined;
157 - // Avoid this attempting to be serialized.
158 - case 'toJSON':
159 - return undefined;
160 - case Symbol.toPrimitive:
161 - // $FlowFixMe[prop-missing]
162 - return Object.prototype[Symbol.toPrimitive];
163 - case '__esModule':
164 - // Something is conditionally checking which export to use. We'll pretend to be
165 - // an ESM compat module but then we'll check again on the client.
166 - const moduleId = target.$$id;
167 - target.default = registerClientReferenceImpl(
168 - (function () {
169 - throw new Error(
170 - `Attempted to call the default export of ${moduleId} from the server ` +
171 - `but it's on the client. It's not possible to invoke a client function from ` +
172 - `the server, it can only be rendered as a Component or passed to props of a ` +
173 - `Client Component.`,
174 - );
175 - }: any),
176 - target.$$id + '#',
177 - target.$$async,
178 - );
179 - return true;
180 - case 'then':
181 - if (target.then) {
182 - // Use a cached value
183 - return target.then;
184 - }
185 - if (!target.$$async) {
186 - // If this module is expected to return a Promise (such as an AsyncModule) then
187 - // we should resolve that with a client reference that unwraps the Promise on
188 - // the client.
189 -
190 - const clientReference: ClientReference<any> =
191 - registerClientReferenceImpl(({}: any), target.$$id, true);
192 - const proxy = new Proxy(clientReference, proxyHandlers);
193 -
194 - // Treat this as a resolved Promise for React's use()
195 - target.status = 'fulfilled';
196 - target.value = proxy;
197 -
198 - const then = (target.then = registerClientReferenceImpl(
199 - (function then(resolve, reject: any) {
200 - // Expose to React.
201 - return Promise.resolve(resolve(proxy));
202 - }: any),
203 - // If this is not used as a Promise but is treated as a reference to a `.then`
204 - // export then we should treat it as a reference to that name.
205 - target.$$id + '#then',
206 - false,
207 - ));
208 - return then;
209 - } else {
210 - // Since typeof .then === 'function' is a feature test we'd continue recursing
211 - // indefinitely if we return a function. Instead, we return an object reference
212 - // if we check further.
213 - return undefined;
214 - }
215 - }
216 - let cachedReference = target[name];
217 - if (!cachedReference) {
218 - const reference: ClientReference<any> = registerClientReferenceImpl(
137 +function getReference(target: Function, name: string): $FlowFixMe {
138 + switch (name) {
139 + // These names are read by the Flight runtime if you end up using the exports object.
140 + case '$$typeof':
141 + return target.$$typeof;
142 + case '$$id':
143 + return target.$$id;
144 + case '$$async':
145 + return target.$$async;
146 + case 'name':
147 + return target.name;
148 + // We need to special case this because createElement reads it if we pass this
149 + // reference.
150 + case 'defaultProps':
151 + return undefined;
152 + // Avoid this attempting to be serialized.
153 + case 'toJSON':
154 + return undefined;
155 + case Symbol.toPrimitive:
156 + // $FlowFixMe[prop-missing]
157 + return Object.prototype[Symbol.toPrimitive];
158 + case '__esModule':
159 + // Something is conditionally checking which export to use. We'll pretend to be
160 + // an ESM compat module but then we'll check again on the client.
161 + const moduleId = target.$$id;
162 + target.default = registerClientReferenceImpl(
163 (function () {
164 throw new Error(
221 - // eslint-disable-next-line react-internal/safe-string-coercion
222 - `Attempted to call ${String(name)}() from the server but ${String(
223 - name,
224 - )} is on the client. ` +
225 - `It's not possible to invoke a client function from the server, it can ` +
226 - `only be rendered as a Component or passed to props of a Client Component.`,
165 + `Attempted to call the default export of ${moduleId} from the server ` +
166 + `but it's on the client. It's not possible to invoke a client function from ` +
167 + `the server, it can only be rendered as a Component or passed to props of a ` +
168 + `Client Component.`,
169 );
170 }: any),
229 - target.$$id + '#' + name,
171 + target.$$id + '#',
172 target.$$async,
173 );
232 - Object.defineProperty((reference: any), 'name', {value: name});
233 - cachedReference = target[name] = new Proxy(reference, deepProxyHandlers);
174 + return true;
175 + case 'then':
176 + if (target.then) {
177 + // Use a cached value
178 + return target.then;
179 + }
180 + if (!target.$$async) {
181 + // If this module is expected to return a Promise (such as an AsyncModule) then
182 + // we should resolve that with a client reference that unwraps the Promise on
183 + // the client.
184 +
185 + const clientReference: ClientReference<any> =
186 + registerClientReferenceImpl(({}: any), target.$$id, true);
187 + const proxy = new Proxy(clientReference, proxyHandlers);
188 +
189 + // Treat this as a resolved Promise for React's use()
190 + target.status = 'fulfilled';
191 + target.value = proxy;
192 +
193 + const then = (target.then = registerClientReferenceImpl(
194 + (function then(resolve, reject: any) {
195 + // Expose to React.
196 + return Promise.resolve(resolve(proxy));
197 + }: any),
198 + // If this is not used as a Promise but is treated as a reference to a `.then`
199 + // export then we should treat it as a reference to that name.
200 + target.$$id + '#then',
201 + false,
202 + ));
203 + return then;
204 + } else {
205 + // Since typeof .then === 'function' is a feature test we'd continue recursing
206 + // indefinitely if we return a function. Instead, we return an object reference
207 + // if we check further.
208 + return undefined;
209 + }
210 + }
211 + let cachedReference = target[name];
212 + if (!cachedReference) {
213 + const reference: ClientReference<any> = registerClientReferenceImpl(
214 + (function () {
215 + throw new Error(
216 + // eslint-disable-next-line react-internal/safe-string-coercion
217 + `Attempted to call ${String(name)}() from the server but ${String(
218 + name,
219 + )} is on the client. ` +
220 + `It's not possible to invoke a client function from the server, it can ` +
221 + `only be rendered as a Component or passed to props of a Client Component.`,
222 + );
223 + }: any),
224 + target.$$id + '#' + name,
225 + target.$$async,
226 + );
227 + Object.defineProperty((reference: any), 'name', {value: name});
228 + cachedReference = target[name] = new Proxy(reference, deepProxyHandlers);
229 + }
230 + return cachedReference;
231 +}
232 +
233 +const proxyHandlers = {
234 + get: function (
235 + target: Function,
236 + name: string,
237 + receiver: Proxy<Function>,
238 + ): $FlowFixMe {
239 + return getReference(target, name);
240 + },
241 + getOwnPropertyDescriptor: function (
242 + target: Function,
243 + name: string,
244 + ): $FlowFixMe {
245 + let descriptor = Object.getOwnPropertyDescriptor(target, name);
246 + if (!descriptor) {
247 + descriptor = {
248 + value: getReference(target, name),
249 + writable: false,
250 + configurable: false,
251 + enumerable: false,
252 + };
253 + Object.defineProperty(target, name, descriptor);
254 }
235 - return cachedReference;
255 + return descriptor;
256 },
257 getPrototypeOf(target: Function): Object {
258 // Pretend to be a Promise in case anyone asks.