[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.