react-server-dom-webpack 18.3.0-next-fa4314841-20230502 → 19.0.0-canary-05797cceb-20240328
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/react-server-dom-webpack-client.browser.development.js +1768 -1188
- package/cjs/react-server-dom-webpack-client.browser.production.js +1739 -0
- package/cjs/react-server-dom-webpack-client.browser.production.min.js +40 -34
- package/cjs/react-server-dom-webpack-client.browser.production.min.js.map +1 -0
- package/cjs/react-server-dom-webpack-client.edge.development.js +1755 -221
- package/cjs/react-server-dom-webpack-client.edge.production.js +1986 -0
- package/cjs/react-server-dom-webpack-client.edge.production.min.js +45 -28
- package/cjs/react-server-dom-webpack-client.edge.production.min.js.map +1 -0
- package/cjs/react-server-dom-webpack-client.node.development.js +1743 -239
- package/cjs/react-server-dom-webpack-client.node.production.js +1942 -0
- package/cjs/react-server-dom-webpack-client.node.production.min.js +44 -28
- package/cjs/react-server-dom-webpack-client.node.production.min.js.map +1 -0
- package/cjs/react-server-dom-webpack-client.node.unbundled.development.js +1702 -194
- package/cjs/react-server-dom-webpack-client.node.unbundled.production.js +1895 -0
- package/cjs/react-server-dom-webpack-client.node.unbundled.production.min.js +43 -26
- package/cjs/react-server-dom-webpack-client.node.unbundled.production.min.js.map +1 -0
- package/cjs/react-server-dom-webpack-node-register.js +12 -18
- package/cjs/react-server-dom-webpack-node-register.js.map +1 -0
- package/cjs/react-server-dom-webpack-plugin.js +22 -19
- package/cjs/react-server-dom-webpack-plugin.js.map +1 -0
- package/cjs/react-server-dom-webpack-server.browser.development.js +1588 -808
- package/cjs/react-server-dom-webpack-server.browser.production.js +3257 -0
- package/cjs/react-server-dom-webpack-server.browser.production.min.js +80 -62
- package/cjs/react-server-dom-webpack-server.browser.production.min.js.map +1 -0
- package/cjs/react-server-dom-webpack-server.edge.development.js +1583 -811
- package/cjs/react-server-dom-webpack-server.edge.production.js +3261 -0
- package/cjs/react-server-dom-webpack-server.edge.production.min.js +82 -62
- package/cjs/react-server-dom-webpack-server.edge.production.min.js.map +1 -0
- package/cjs/react-server-dom-webpack-server.node.development.js +1575 -805
- package/cjs/react-server-dom-webpack-server.node.production.js +3464 -0
- package/cjs/react-server-dom-webpack-server.node.production.min.js +85 -67
- package/cjs/react-server-dom-webpack-server.node.production.min.js.map +1 -0
- package/cjs/react-server-dom-webpack-server.node.unbundled.development.js +1526 -761
- package/cjs/react-server-dom-webpack-server.node.unbundled.production.js +3391 -0
- package/cjs/react-server-dom-webpack-server.node.unbundled.production.min.js +82 -65
- package/cjs/react-server-dom-webpack-server.node.unbundled.production.min.js.map +1 -0
- package/esm/react-server-dom-webpack-node-loader.production.min.js +19 -12
- package/package.json +7 -13
- package/umd/react-server-dom-webpack-client.browser.development.js +1770 -1189
- package/umd/react-server-dom-webpack-client.browser.production.min.js +26 -20
- package/umd/react-server-dom-webpack-server.browser.development.js +1589 -808
- package/umd/react-server-dom-webpack-server.browser.production.min.js +55 -42
@@ -0,0 +1,1895 @@
|
|
1
|
+
/**
|
2
|
+
* @license React
|
3
|
+
* react-server-dom-webpack-client.node.unbundled.production.min.js
|
4
|
+
*
|
5
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
6
|
+
*
|
7
|
+
* This source code is licensed under the MIT license found in the
|
8
|
+
* LICENSE file in the root directory of this source tree.
|
9
|
+
*/
|
10
|
+
|
11
|
+
'use strict';
|
12
|
+
|
13
|
+
var util = require('util');
|
14
|
+
var ReactDOM = require('react-dom');
|
15
|
+
|
16
|
+
// -----------------------------------------------------------------------------
|
17
|
+
const enableBinaryFlight = false;
|
18
|
+
|
19
|
+
function createStringDecoder() {
|
20
|
+
return new util.TextDecoder();
|
21
|
+
}
|
22
|
+
const decoderOptions = {
|
23
|
+
stream: true
|
24
|
+
};
|
25
|
+
function readPartialStringChunk(decoder, buffer) {
|
26
|
+
return decoder.decode(buffer, decoderOptions);
|
27
|
+
}
|
28
|
+
function readFinalStringChunk(decoder, buffer) {
|
29
|
+
return decoder.decode(buffer);
|
30
|
+
}
|
31
|
+
|
32
|
+
// This is the parsed shape of the wire format which is why it is
|
33
|
+
// condensed to only the essentialy information
|
34
|
+
const ID = 0;
|
35
|
+
const CHUNKS = 1;
|
36
|
+
const NAME = 2; // export const ASYNC = 3;
|
37
|
+
// This logic is correct because currently only include the 4th tuple member
|
38
|
+
// when the module is async. If that changes we will need to actually assert
|
39
|
+
// the value is true. We don't index into the 4th slot because flow does not
|
40
|
+
// like the potential out of bounds access
|
41
|
+
|
42
|
+
function isAsyncImport(metadata) {
|
43
|
+
return metadata.length === 4;
|
44
|
+
}
|
45
|
+
|
46
|
+
// The reason this function needs to defined here in this file instead of just
|
47
|
+
// being exported directly from the WebpackDestination... file is because the
|
48
|
+
// ClientReferenceMetadata is opaque and we can't unwrap it there.
|
49
|
+
// This should get inlined and we could also just implement an unwrapping function
|
50
|
+
// though that risks it getting used in places it shouldn't be. This is unfortunate
|
51
|
+
// but currently it seems to be the best option we have.
|
52
|
+
|
53
|
+
function prepareDestinationForModule(moduleLoading, nonce, metadata) {
|
54
|
+
prepareDestinationWithChunks(moduleLoading, metadata[CHUNKS], nonce);
|
55
|
+
}
|
56
|
+
function resolveClientReference(bundlerConfig, metadata) {
|
57
|
+
const moduleExports = bundlerConfig[metadata[ID]];
|
58
|
+
let resolvedModuleData = moduleExports[metadata[NAME]];
|
59
|
+
let name;
|
60
|
+
|
61
|
+
if (resolvedModuleData) {
|
62
|
+
// The potentially aliased name.
|
63
|
+
name = resolvedModuleData.name;
|
64
|
+
} else {
|
65
|
+
// If we don't have this specific name, we might have the full module.
|
66
|
+
resolvedModuleData = moduleExports['*'];
|
67
|
+
|
68
|
+
if (!resolvedModuleData) {
|
69
|
+
throw new Error('Could not find the module "' + metadata[ID] + '" in the React SSR Manifest. ' + 'This is probably a bug in the React Server Components bundler.');
|
70
|
+
}
|
71
|
+
|
72
|
+
name = metadata[NAME];
|
73
|
+
}
|
74
|
+
|
75
|
+
return {
|
76
|
+
specifier: resolvedModuleData.specifier,
|
77
|
+
name: name,
|
78
|
+
async: isAsyncImport(metadata)
|
79
|
+
};
|
80
|
+
}
|
81
|
+
const asyncModuleCache = new Map();
|
82
|
+
function preloadModule(metadata) {
|
83
|
+
const existingPromise = asyncModuleCache.get(metadata.specifier);
|
84
|
+
|
85
|
+
if (existingPromise) {
|
86
|
+
if (existingPromise.status === 'fulfilled') {
|
87
|
+
return null;
|
88
|
+
}
|
89
|
+
|
90
|
+
return existingPromise;
|
91
|
+
} else {
|
92
|
+
// $FlowFixMe[unsupported-syntax]
|
93
|
+
let modulePromise = import(metadata.specifier);
|
94
|
+
|
95
|
+
if (metadata.async) {
|
96
|
+
// If the module is async, it must have been a CJS module.
|
97
|
+
// CJS modules are accessed through the default export in
|
98
|
+
// Node.js so we have to get the default export to get the
|
99
|
+
// full module exports.
|
100
|
+
modulePromise = modulePromise.then(function (value) {
|
101
|
+
return value.default;
|
102
|
+
});
|
103
|
+
}
|
104
|
+
|
105
|
+
modulePromise.then(value => {
|
106
|
+
const fulfilledThenable = modulePromise;
|
107
|
+
fulfilledThenable.status = 'fulfilled';
|
108
|
+
fulfilledThenable.value = value;
|
109
|
+
}, reason => {
|
110
|
+
const rejectedThenable = modulePromise;
|
111
|
+
rejectedThenable.status = 'rejected';
|
112
|
+
rejectedThenable.reason = reason;
|
113
|
+
});
|
114
|
+
asyncModuleCache.set(metadata.specifier, modulePromise);
|
115
|
+
return modulePromise;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
function requireModule(metadata) {
|
119
|
+
let moduleExports; // We assume that preloadModule has been called before, which
|
120
|
+
// should have added something to the module cache.
|
121
|
+
|
122
|
+
const promise = asyncModuleCache.get(metadata.specifier);
|
123
|
+
|
124
|
+
if (promise.status === 'fulfilled') {
|
125
|
+
moduleExports = promise.value;
|
126
|
+
} else {
|
127
|
+
throw promise.reason;
|
128
|
+
}
|
129
|
+
|
130
|
+
if (metadata.name === '*') {
|
131
|
+
// This is a placeholder value that represents that the caller imported this
|
132
|
+
// as a CommonJS module as is.
|
133
|
+
return moduleExports;
|
134
|
+
}
|
135
|
+
|
136
|
+
if (metadata.name === '') {
|
137
|
+
// This is a placeholder value that represents that the caller accessed the
|
138
|
+
// default property of this if it was an ESM interop module.
|
139
|
+
return moduleExports.default;
|
140
|
+
}
|
141
|
+
|
142
|
+
return moduleExports[metadata.name];
|
143
|
+
}
|
144
|
+
|
145
|
+
function prepareDestinationWithChunks(moduleLoading, // Chunks are double-indexed [..., idx, filenamex, idy, filenamey, ...]
|
146
|
+
chunks, nonce) {
|
147
|
+
if (moduleLoading !== null) {
|
148
|
+
for (let i = 1; i < chunks.length; i += 2) {
|
149
|
+
preinitScriptForSSR(moduleLoading.prefix + chunks[i], nonce, moduleLoading.crossOrigin);
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
const ReactDOMSharedInternals = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
155
|
+
|
156
|
+
function getCrossOriginString(input) {
|
157
|
+
if (typeof input === 'string') {
|
158
|
+
return input === 'use-credentials' ? input : '';
|
159
|
+
}
|
160
|
+
|
161
|
+
return undefined;
|
162
|
+
}
|
163
|
+
|
164
|
+
// This client file is in the shared folder because it applies to both SSR and browser contexts.
|
165
|
+
const ReactDOMCurrentDispatcher = ReactDOMSharedInternals.ReactDOMCurrentDispatcher;
|
166
|
+
function dispatchHint(code, model) {
|
167
|
+
const dispatcher = ReactDOMCurrentDispatcher.current;
|
168
|
+
|
169
|
+
switch (code) {
|
170
|
+
case 'D':
|
171
|
+
{
|
172
|
+
const refined = refineModel(code, model);
|
173
|
+
const href = refined;
|
174
|
+
dispatcher.prefetchDNS(href);
|
175
|
+
return;
|
176
|
+
}
|
177
|
+
|
178
|
+
case 'C':
|
179
|
+
{
|
180
|
+
const refined = refineModel(code, model);
|
181
|
+
|
182
|
+
if (typeof refined === 'string') {
|
183
|
+
const href = refined;
|
184
|
+
dispatcher.preconnect(href);
|
185
|
+
} else {
|
186
|
+
const href = refined[0];
|
187
|
+
const crossOrigin = refined[1];
|
188
|
+
dispatcher.preconnect(href, crossOrigin);
|
189
|
+
}
|
190
|
+
|
191
|
+
return;
|
192
|
+
}
|
193
|
+
|
194
|
+
case 'L':
|
195
|
+
{
|
196
|
+
const refined = refineModel(code, model);
|
197
|
+
const href = refined[0];
|
198
|
+
const as = refined[1];
|
199
|
+
|
200
|
+
if (refined.length === 3) {
|
201
|
+
const options = refined[2];
|
202
|
+
dispatcher.preload(href, as, options);
|
203
|
+
} else {
|
204
|
+
dispatcher.preload(href, as);
|
205
|
+
}
|
206
|
+
|
207
|
+
return;
|
208
|
+
}
|
209
|
+
|
210
|
+
case 'm':
|
211
|
+
{
|
212
|
+
const refined = refineModel(code, model);
|
213
|
+
|
214
|
+
if (typeof refined === 'string') {
|
215
|
+
const href = refined;
|
216
|
+
dispatcher.preloadModule(href);
|
217
|
+
} else {
|
218
|
+
const href = refined[0];
|
219
|
+
const options = refined[1];
|
220
|
+
dispatcher.preloadModule(href, options);
|
221
|
+
}
|
222
|
+
|
223
|
+
return;
|
224
|
+
}
|
225
|
+
|
226
|
+
case 'S':
|
227
|
+
{
|
228
|
+
const refined = refineModel(code, model);
|
229
|
+
|
230
|
+
if (typeof refined === 'string') {
|
231
|
+
const href = refined;
|
232
|
+
dispatcher.preinitStyle(href);
|
233
|
+
} else {
|
234
|
+
const href = refined[0];
|
235
|
+
const precedence = refined[1] === 0 ? undefined : refined[1];
|
236
|
+
const options = refined.length === 3 ? refined[2] : undefined;
|
237
|
+
dispatcher.preinitStyle(href, precedence, options);
|
238
|
+
}
|
239
|
+
|
240
|
+
return;
|
241
|
+
}
|
242
|
+
|
243
|
+
case 'X':
|
244
|
+
{
|
245
|
+
const refined = refineModel(code, model);
|
246
|
+
|
247
|
+
if (typeof refined === 'string') {
|
248
|
+
const href = refined;
|
249
|
+
dispatcher.preinitScript(href);
|
250
|
+
} else {
|
251
|
+
const href = refined[0];
|
252
|
+
const options = refined[1];
|
253
|
+
dispatcher.preinitScript(href, options);
|
254
|
+
}
|
255
|
+
|
256
|
+
return;
|
257
|
+
}
|
258
|
+
|
259
|
+
case 'M':
|
260
|
+
{
|
261
|
+
const refined = refineModel(code, model);
|
262
|
+
|
263
|
+
if (typeof refined === 'string') {
|
264
|
+
const href = refined;
|
265
|
+
dispatcher.preinitModuleScript(href);
|
266
|
+
} else {
|
267
|
+
const href = refined[0];
|
268
|
+
const options = refined[1];
|
269
|
+
dispatcher.preinitModuleScript(href, options);
|
270
|
+
}
|
271
|
+
|
272
|
+
return;
|
273
|
+
}
|
274
|
+
}
|
275
|
+
} // Flow is having trouble refining the HintModels so we help it a bit.
|
276
|
+
// This should be compiled out in the production build.
|
277
|
+
|
278
|
+
function refineModel(code, model) {
|
279
|
+
return model;
|
280
|
+
}
|
281
|
+
function preinitScriptForSSR(href, nonce, crossOrigin) {
|
282
|
+
const dispatcher = ReactDOMCurrentDispatcher.current;
|
283
|
+
|
284
|
+
if (dispatcher) {
|
285
|
+
dispatcher.preinitScript(href, {
|
286
|
+
crossOrigin: getCrossOriginString(crossOrigin),
|
287
|
+
nonce
|
288
|
+
});
|
289
|
+
}
|
290
|
+
}
|
291
|
+
|
292
|
+
// ATTENTION
|
293
|
+
// When adding new symbols to this file,
|
294
|
+
// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
|
295
|
+
// The Symbol used to tag the ReactElement-like types.
|
296
|
+
const REACT_ELEMENT_TYPE = Symbol.for('react.element');
|
297
|
+
const REACT_LAZY_TYPE = Symbol.for('react.lazy');
|
298
|
+
const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
|
299
|
+
const FAUX_ITERATOR_SYMBOL = '@@iterator';
|
300
|
+
function getIteratorFn(maybeIterable) {
|
301
|
+
if (maybeIterable === null || typeof maybeIterable !== 'object') {
|
302
|
+
return null;
|
303
|
+
}
|
304
|
+
|
305
|
+
const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
|
306
|
+
|
307
|
+
if (typeof maybeIterator === 'function') {
|
308
|
+
return maybeIterator;
|
309
|
+
}
|
310
|
+
|
311
|
+
return null;
|
312
|
+
}
|
313
|
+
|
314
|
+
const isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare
|
315
|
+
|
316
|
+
function isArray(a) {
|
317
|
+
return isArrayImpl(a);
|
318
|
+
}
|
319
|
+
|
320
|
+
const getPrototypeOf = Object.getPrototypeOf;
|
321
|
+
|
322
|
+
function writeTemporaryReference(set, object) {
|
323
|
+
// We always create a new entry regardless if we've already written the same
|
324
|
+
// object. This ensures that we always generate a deterministic encoding of
|
325
|
+
// each slot in the reply for cacheability.
|
326
|
+
const newId = set.length;
|
327
|
+
set.push(object);
|
328
|
+
return newId;
|
329
|
+
}
|
330
|
+
function readTemporaryReference(set, id) {
|
331
|
+
if (id < 0 || id >= set.length) {
|
332
|
+
throw new Error("The RSC response contained a reference that doesn't exist in the temporary reference set. " + 'Always pass the matching set that was used to create the reply when parsing its response.');
|
333
|
+
}
|
334
|
+
|
335
|
+
return set[id];
|
336
|
+
}
|
337
|
+
|
338
|
+
const ObjectPrototype = Object.prototype;
|
339
|
+
const knownServerReferences = new WeakMap(); // Serializable values
|
340
|
+
// Thenable<ReactServerValue>
|
341
|
+
|
342
|
+
function serializeByValueID(id) {
|
343
|
+
return '$' + id.toString(16);
|
344
|
+
}
|
345
|
+
|
346
|
+
function serializePromiseID(id) {
|
347
|
+
return '$@' + id.toString(16);
|
348
|
+
}
|
349
|
+
|
350
|
+
function serializeServerReferenceID(id) {
|
351
|
+
return '$F' + id.toString(16);
|
352
|
+
}
|
353
|
+
|
354
|
+
function serializeTemporaryReferenceID(id) {
|
355
|
+
return '$T' + id.toString(16);
|
356
|
+
}
|
357
|
+
|
358
|
+
function serializeFormDataReference(id) {
|
359
|
+
// Why K? F is "Function". D is "Date". What else?
|
360
|
+
return '$K' + id.toString(16);
|
361
|
+
}
|
362
|
+
|
363
|
+
function serializeNumber(number) {
|
364
|
+
if (Number.isFinite(number)) {
|
365
|
+
if (number === 0 && 1 / number === -Infinity) {
|
366
|
+
return '$-0';
|
367
|
+
} else {
|
368
|
+
return number;
|
369
|
+
}
|
370
|
+
} else {
|
371
|
+
if (number === Infinity) {
|
372
|
+
return '$Infinity';
|
373
|
+
} else if (number === -Infinity) {
|
374
|
+
return '$-Infinity';
|
375
|
+
} else {
|
376
|
+
return '$NaN';
|
377
|
+
}
|
378
|
+
}
|
379
|
+
}
|
380
|
+
|
381
|
+
function serializeUndefined() {
|
382
|
+
return '$undefined';
|
383
|
+
}
|
384
|
+
|
385
|
+
function serializeDateFromDateJSON(dateJSON) {
|
386
|
+
// JSON.stringify automatically calls Date.prototype.toJSON which calls toISOString.
|
387
|
+
// We need only tack on a $D prefix.
|
388
|
+
return '$D' + dateJSON;
|
389
|
+
}
|
390
|
+
|
391
|
+
function serializeBigInt(n) {
|
392
|
+
return '$n' + n.toString(10);
|
393
|
+
}
|
394
|
+
|
395
|
+
function serializeMapID(id) {
|
396
|
+
return '$Q' + id.toString(16);
|
397
|
+
}
|
398
|
+
|
399
|
+
function serializeSetID(id) {
|
400
|
+
return '$W' + id.toString(16);
|
401
|
+
}
|
402
|
+
|
403
|
+
function escapeStringValue(value) {
|
404
|
+
if (value[0] === '$') {
|
405
|
+
// We need to escape $ prefixed strings since we use those to encode
|
406
|
+
// references to IDs and as special symbol values.
|
407
|
+
return '$' + value;
|
408
|
+
} else {
|
409
|
+
return value;
|
410
|
+
}
|
411
|
+
}
|
412
|
+
|
413
|
+
function processReply(root, formFieldPrefix, temporaryReferences, resolve, reject) {
|
414
|
+
let nextPartId = 1;
|
415
|
+
let pendingParts = 0;
|
416
|
+
let formData = null;
|
417
|
+
|
418
|
+
function resolveToJSON(key, value) {
|
419
|
+
const parent = this; // Make sure that `parent[key]` wasn't JSONified before `value` was passed to us
|
420
|
+
|
421
|
+
if (value === null) {
|
422
|
+
return null;
|
423
|
+
}
|
424
|
+
|
425
|
+
if (typeof value === 'object') {
|
426
|
+
switch (value.$$typeof) {
|
427
|
+
case REACT_ELEMENT_TYPE:
|
428
|
+
{
|
429
|
+
if (temporaryReferences === undefined) {
|
430
|
+
throw new Error('React Element cannot be passed to Server Functions from the Client without a ' + 'temporary reference set. Pass a TemporaryReferenceSet to the options.' + (''));
|
431
|
+
}
|
432
|
+
|
433
|
+
return serializeTemporaryReferenceID(writeTemporaryReference(temporaryReferences, value));
|
434
|
+
}
|
435
|
+
|
436
|
+
case REACT_LAZY_TYPE:
|
437
|
+
{
|
438
|
+
// Resolve lazy as if it wasn't here. In the future this will be encoded as a Promise.
|
439
|
+
const lazy = value;
|
440
|
+
const payload = lazy._payload;
|
441
|
+
const init = lazy._init;
|
442
|
+
|
443
|
+
if (formData === null) {
|
444
|
+
// Upgrade to use FormData to allow us to stream this value.
|
445
|
+
formData = new FormData();
|
446
|
+
}
|
447
|
+
|
448
|
+
pendingParts++;
|
449
|
+
|
450
|
+
try {
|
451
|
+
const resolvedModel = init(payload); // We always outline this as a separate part even though we could inline it
|
452
|
+
// because it ensures a more deterministic encoding.
|
453
|
+
|
454
|
+
const lazyId = nextPartId++;
|
455
|
+
const partJSON = JSON.stringify(resolvedModel, resolveToJSON); // $FlowFixMe[incompatible-type] We know it's not null because we assigned it above.
|
456
|
+
|
457
|
+
const data = formData; // eslint-disable-next-line react-internal/safe-string-coercion
|
458
|
+
|
459
|
+
data.append(formFieldPrefix + lazyId, partJSON);
|
460
|
+
return serializeByValueID(lazyId);
|
461
|
+
} catch (x) {
|
462
|
+
if (typeof x === 'object' && x !== null && typeof x.then === 'function') {
|
463
|
+
// Suspended
|
464
|
+
pendingParts++;
|
465
|
+
const lazyId = nextPartId++;
|
466
|
+
const thenable = x;
|
467
|
+
|
468
|
+
const retry = function () {
|
469
|
+
// While the first promise resolved, its value isn't necessarily what we'll
|
470
|
+
// resolve into because we might suspend again.
|
471
|
+
try {
|
472
|
+
const partJSON = JSON.stringify(value, resolveToJSON); // $FlowFixMe[incompatible-type] We know it's not null because we assigned it above.
|
473
|
+
|
474
|
+
const data = formData; // eslint-disable-next-line react-internal/safe-string-coercion
|
475
|
+
|
476
|
+
data.append(formFieldPrefix + lazyId, partJSON);
|
477
|
+
pendingParts--;
|
478
|
+
|
479
|
+
if (pendingParts === 0) {
|
480
|
+
resolve(data);
|
481
|
+
}
|
482
|
+
} catch (reason) {
|
483
|
+
reject(reason);
|
484
|
+
}
|
485
|
+
};
|
486
|
+
|
487
|
+
thenable.then(retry, retry);
|
488
|
+
return serializeByValueID(lazyId);
|
489
|
+
} else {
|
490
|
+
// In the future we could consider serializing this as an error
|
491
|
+
// that throws on the server instead.
|
492
|
+
reject(x);
|
493
|
+
return null;
|
494
|
+
}
|
495
|
+
} finally {
|
496
|
+
pendingParts--;
|
497
|
+
}
|
498
|
+
}
|
499
|
+
} // $FlowFixMe[method-unbinding]
|
500
|
+
|
501
|
+
|
502
|
+
if (typeof value.then === 'function') {
|
503
|
+
// We assume that any object with a .then property is a "Thenable" type,
|
504
|
+
// or a Promise type. Either of which can be represented by a Promise.
|
505
|
+
if (formData === null) {
|
506
|
+
// Upgrade to use FormData to allow us to stream this value.
|
507
|
+
formData = new FormData();
|
508
|
+
}
|
509
|
+
|
510
|
+
pendingParts++;
|
511
|
+
const promiseId = nextPartId++;
|
512
|
+
const thenable = value;
|
513
|
+
thenable.then(partValue => {
|
514
|
+
try {
|
515
|
+
const partJSON = JSON.stringify(partValue, resolveToJSON); // $FlowFixMe[incompatible-type] We know it's not null because we assigned it above.
|
516
|
+
|
517
|
+
const data = formData; // eslint-disable-next-line react-internal/safe-string-coercion
|
518
|
+
|
519
|
+
data.append(formFieldPrefix + promiseId, partJSON);
|
520
|
+
pendingParts--;
|
521
|
+
|
522
|
+
if (pendingParts === 0) {
|
523
|
+
resolve(data);
|
524
|
+
}
|
525
|
+
} catch (reason) {
|
526
|
+
reject(reason);
|
527
|
+
}
|
528
|
+
}, reason => {
|
529
|
+
// In the future we could consider serializing this as an error
|
530
|
+
// that throws on the server instead.
|
531
|
+
reject(reason);
|
532
|
+
});
|
533
|
+
return serializePromiseID(promiseId);
|
534
|
+
}
|
535
|
+
|
536
|
+
if (isArray(value)) {
|
537
|
+
// $FlowFixMe[incompatible-return]
|
538
|
+
return value;
|
539
|
+
} // TODO: Should we the Object.prototype.toString.call() to test for cross-realm objects?
|
540
|
+
|
541
|
+
|
542
|
+
if (value instanceof FormData) {
|
543
|
+
if (formData === null) {
|
544
|
+
// Upgrade to use FormData to allow us to use rich objects as its values.
|
545
|
+
formData = new FormData();
|
546
|
+
}
|
547
|
+
|
548
|
+
const data = formData;
|
549
|
+
const refId = nextPartId++; // Copy all the form fields with a prefix for this reference.
|
550
|
+
// These must come first in the form order because we assume that all the
|
551
|
+
// fields are available before this is referenced.
|
552
|
+
|
553
|
+
const prefix = formFieldPrefix + refId + '_'; // $FlowFixMe[prop-missing]: FormData has forEach.
|
554
|
+
|
555
|
+
value.forEach((originalValue, originalKey) => {
|
556
|
+
data.append(prefix + originalKey, originalValue);
|
557
|
+
});
|
558
|
+
return serializeFormDataReference(refId);
|
559
|
+
}
|
560
|
+
|
561
|
+
if (value instanceof Map) {
|
562
|
+
const partJSON = JSON.stringify(Array.from(value), resolveToJSON);
|
563
|
+
|
564
|
+
if (formData === null) {
|
565
|
+
formData = new FormData();
|
566
|
+
}
|
567
|
+
|
568
|
+
const mapId = nextPartId++;
|
569
|
+
formData.append(formFieldPrefix + mapId, partJSON);
|
570
|
+
return serializeMapID(mapId);
|
571
|
+
}
|
572
|
+
|
573
|
+
if (value instanceof Set) {
|
574
|
+
const partJSON = JSON.stringify(Array.from(value), resolveToJSON);
|
575
|
+
|
576
|
+
if (formData === null) {
|
577
|
+
formData = new FormData();
|
578
|
+
}
|
579
|
+
|
580
|
+
const setId = nextPartId++;
|
581
|
+
formData.append(formFieldPrefix + setId, partJSON);
|
582
|
+
return serializeSetID(setId);
|
583
|
+
}
|
584
|
+
|
585
|
+
const iteratorFn = getIteratorFn(value);
|
586
|
+
|
587
|
+
if (iteratorFn) {
|
588
|
+
return Array.from(value);
|
589
|
+
} // Verify that this is a simple plain object.
|
590
|
+
|
591
|
+
|
592
|
+
const proto = getPrototypeOf(value);
|
593
|
+
|
594
|
+
if (proto !== ObjectPrototype && (proto === null || getPrototypeOf(proto) !== null)) {
|
595
|
+
if (temporaryReferences === undefined) {
|
596
|
+
throw new Error('Only plain objects, and a few built-ins, can be passed to Server Actions. ' + 'Classes or null prototypes are not supported.');
|
597
|
+
} // We can serialize class instances as temporary references.
|
598
|
+
|
599
|
+
|
600
|
+
return serializeTemporaryReferenceID(writeTemporaryReference(temporaryReferences, value));
|
601
|
+
}
|
602
|
+
|
603
|
+
|
604
|
+
return value;
|
605
|
+
}
|
606
|
+
|
607
|
+
if (typeof value === 'string') {
|
608
|
+
// TODO: Maybe too clever. If we support URL there's no similar trick.
|
609
|
+
if (value[value.length - 1] === 'Z') {
|
610
|
+
// Possibly a Date, whose toJSON automatically calls toISOString
|
611
|
+
// $FlowFixMe[incompatible-use]
|
612
|
+
const originalValue = parent[key];
|
613
|
+
|
614
|
+
if (originalValue instanceof Date) {
|
615
|
+
return serializeDateFromDateJSON(value);
|
616
|
+
}
|
617
|
+
}
|
618
|
+
|
619
|
+
return escapeStringValue(value);
|
620
|
+
}
|
621
|
+
|
622
|
+
if (typeof value === 'boolean') {
|
623
|
+
return value;
|
624
|
+
}
|
625
|
+
|
626
|
+
if (typeof value === 'number') {
|
627
|
+
return serializeNumber(value);
|
628
|
+
}
|
629
|
+
|
630
|
+
if (typeof value === 'undefined') {
|
631
|
+
return serializeUndefined();
|
632
|
+
}
|
633
|
+
|
634
|
+
if (typeof value === 'function') {
|
635
|
+
const metaData = knownServerReferences.get(value);
|
636
|
+
|
637
|
+
if (metaData !== undefined) {
|
638
|
+
const metaDataJSON = JSON.stringify(metaData, resolveToJSON);
|
639
|
+
|
640
|
+
if (formData === null) {
|
641
|
+
// Upgrade to use FormData to allow us to stream this value.
|
642
|
+
formData = new FormData();
|
643
|
+
} // The reference to this function came from the same client so we can pass it back.
|
644
|
+
|
645
|
+
|
646
|
+
const refId = nextPartId++; // eslint-disable-next-line react-internal/safe-string-coercion
|
647
|
+
|
648
|
+
formData.set(formFieldPrefix + refId, metaDataJSON);
|
649
|
+
return serializeServerReferenceID(refId);
|
650
|
+
}
|
651
|
+
|
652
|
+
if (temporaryReferences === undefined) {
|
653
|
+
throw new Error('Client Functions cannot be passed directly to Server Functions. ' + 'Only Functions passed from the Server can be passed back again.');
|
654
|
+
}
|
655
|
+
|
656
|
+
return serializeTemporaryReferenceID(writeTemporaryReference(temporaryReferences, value));
|
657
|
+
}
|
658
|
+
|
659
|
+
if (typeof value === 'symbol') {
|
660
|
+
if (temporaryReferences === undefined) {
|
661
|
+
throw new Error('Symbols cannot be passed to a Server Function without a ' + 'temporary reference set. Pass a TemporaryReferenceSet to the options.' + (''));
|
662
|
+
}
|
663
|
+
|
664
|
+
return serializeTemporaryReferenceID(writeTemporaryReference(temporaryReferences, value));
|
665
|
+
}
|
666
|
+
|
667
|
+
if (typeof value === 'bigint') {
|
668
|
+
return serializeBigInt(value);
|
669
|
+
}
|
670
|
+
|
671
|
+
throw new Error("Type " + typeof value + " is not supported as an argument to a Server Function.");
|
672
|
+
} // $FlowFixMe[incompatible-type] it's not going to be undefined because we'll encode it.
|
673
|
+
|
674
|
+
|
675
|
+
const json = JSON.stringify(root, resolveToJSON);
|
676
|
+
|
677
|
+
if (formData === null) {
|
678
|
+
// If it's a simple data structure, we just use plain JSON.
|
679
|
+
resolve(json);
|
680
|
+
} else {
|
681
|
+
// Otherwise, we use FormData to let us stream in the result.
|
682
|
+
formData.set(formFieldPrefix + '0', json);
|
683
|
+
|
684
|
+
if (pendingParts === 0) {
|
685
|
+
// $FlowFixMe[incompatible-call] this has already been refined.
|
686
|
+
resolve(formData);
|
687
|
+
}
|
688
|
+
}
|
689
|
+
}
|
690
|
+
const boundCache = new WeakMap();
|
691
|
+
|
692
|
+
function encodeFormData(reference) {
|
693
|
+
let resolve, reject; // We need to have a handle on the thenable so that we can synchronously set
|
694
|
+
// its status from processReply, when it can complete synchronously.
|
695
|
+
|
696
|
+
const thenable = new Promise((res, rej) => {
|
697
|
+
resolve = res;
|
698
|
+
reject = rej;
|
699
|
+
});
|
700
|
+
processReply(reference, '', undefined, // TODO: This means React Elements can't be used as state in progressive enhancement.
|
701
|
+
body => {
|
702
|
+
if (typeof body === 'string') {
|
703
|
+
const data = new FormData();
|
704
|
+
data.append('0', body);
|
705
|
+
body = data;
|
706
|
+
}
|
707
|
+
|
708
|
+
const fulfilled = thenable;
|
709
|
+
fulfilled.status = 'fulfilled';
|
710
|
+
fulfilled.value = body;
|
711
|
+
resolve(body);
|
712
|
+
}, e => {
|
713
|
+
const rejected = thenable;
|
714
|
+
rejected.status = 'rejected';
|
715
|
+
rejected.reason = e;
|
716
|
+
reject(e);
|
717
|
+
});
|
718
|
+
return thenable;
|
719
|
+
}
|
720
|
+
|
721
|
+
function defaultEncodeFormAction(identifierPrefix) {
|
722
|
+
const reference = knownServerReferences.get(this);
|
723
|
+
|
724
|
+
if (!reference) {
|
725
|
+
throw new Error('Tried to encode a Server Action from a different instance than the encoder is from. ' + 'This is a bug in React.');
|
726
|
+
}
|
727
|
+
|
728
|
+
let data = null;
|
729
|
+
let name;
|
730
|
+
const boundPromise = reference.bound;
|
731
|
+
|
732
|
+
if (boundPromise !== null) {
|
733
|
+
let thenable = boundCache.get(reference);
|
734
|
+
|
735
|
+
if (!thenable) {
|
736
|
+
thenable = encodeFormData(reference);
|
737
|
+
boundCache.set(reference, thenable);
|
738
|
+
}
|
739
|
+
|
740
|
+
if (thenable.status === 'rejected') {
|
741
|
+
throw thenable.reason;
|
742
|
+
} else if (thenable.status !== 'fulfilled') {
|
743
|
+
throw thenable;
|
744
|
+
}
|
745
|
+
|
746
|
+
const encodedFormData = thenable.value; // This is hacky but we need the identifier prefix to be added to
|
747
|
+
// all fields but the suspense cache would break since we might get
|
748
|
+
// a new identifier each time. So we just append it at the end instead.
|
749
|
+
|
750
|
+
const prefixedData = new FormData(); // $FlowFixMe[prop-missing]
|
751
|
+
|
752
|
+
encodedFormData.forEach((value, key) => {
|
753
|
+
prefixedData.append('$ACTION_' + identifierPrefix + ':' + key, value);
|
754
|
+
});
|
755
|
+
data = prefixedData; // We encode the name of the prefix containing the data.
|
756
|
+
|
757
|
+
name = '$ACTION_REF_' + identifierPrefix;
|
758
|
+
} else {
|
759
|
+
// This is the simple case so we can just encode the ID.
|
760
|
+
name = '$ACTION_ID_' + reference.id;
|
761
|
+
}
|
762
|
+
|
763
|
+
return {
|
764
|
+
name: name,
|
765
|
+
method: 'POST',
|
766
|
+
encType: 'multipart/form-data',
|
767
|
+
data: data
|
768
|
+
};
|
769
|
+
}
|
770
|
+
|
771
|
+
function customEncodeFormAction(proxy, identifierPrefix, encodeFormAction) {
|
772
|
+
const reference = knownServerReferences.get(proxy);
|
773
|
+
|
774
|
+
if (!reference) {
|
775
|
+
throw new Error('Tried to encode a Server Action from a different instance than the encoder is from. ' + 'This is a bug in React.');
|
776
|
+
}
|
777
|
+
|
778
|
+
let boundPromise = reference.bound;
|
779
|
+
|
780
|
+
if (boundPromise === null) {
|
781
|
+
boundPromise = Promise.resolve([]);
|
782
|
+
}
|
783
|
+
|
784
|
+
return encodeFormAction(reference.id, boundPromise);
|
785
|
+
}
|
786
|
+
|
787
|
+
function isSignatureEqual(referenceId, numberOfBoundArgs) {
|
788
|
+
const reference = knownServerReferences.get(this);
|
789
|
+
|
790
|
+
if (!reference) {
|
791
|
+
throw new Error('Tried to encode a Server Action from a different instance than the encoder is from. ' + 'This is a bug in React.');
|
792
|
+
}
|
793
|
+
|
794
|
+
if (reference.id !== referenceId) {
|
795
|
+
// These are different functions.
|
796
|
+
return false;
|
797
|
+
} // Now check if the number of bound arguments is the same.
|
798
|
+
|
799
|
+
|
800
|
+
const boundPromise = reference.bound;
|
801
|
+
|
802
|
+
if (boundPromise === null) {
|
803
|
+
// No bound arguments.
|
804
|
+
return numberOfBoundArgs === 0;
|
805
|
+
} // Unwrap the bound arguments array by suspending, if necessary. As with
|
806
|
+
// encodeFormData, this means isSignatureEqual can only be called while React
|
807
|
+
// is rendering.
|
808
|
+
|
809
|
+
|
810
|
+
switch (boundPromise.status) {
|
811
|
+
case 'fulfilled':
|
812
|
+
{
|
813
|
+
const boundArgs = boundPromise.value;
|
814
|
+
return boundArgs.length === numberOfBoundArgs;
|
815
|
+
}
|
816
|
+
|
817
|
+
case 'pending':
|
818
|
+
{
|
819
|
+
throw boundPromise;
|
820
|
+
}
|
821
|
+
|
822
|
+
case 'rejected':
|
823
|
+
{
|
824
|
+
throw boundPromise.reason;
|
825
|
+
}
|
826
|
+
|
827
|
+
default:
|
828
|
+
{
|
829
|
+
if (typeof boundPromise.status === 'string') ; else {
|
830
|
+
const pendingThenable = boundPromise;
|
831
|
+
pendingThenable.status = 'pending';
|
832
|
+
pendingThenable.then(boundArgs => {
|
833
|
+
const fulfilledThenable = boundPromise;
|
834
|
+
fulfilledThenable.status = 'fulfilled';
|
835
|
+
fulfilledThenable.value = boundArgs;
|
836
|
+
}, error => {
|
837
|
+
const rejectedThenable = boundPromise;
|
838
|
+
rejectedThenable.status = 'rejected';
|
839
|
+
rejectedThenable.reason = error;
|
840
|
+
});
|
841
|
+
}
|
842
|
+
|
843
|
+
throw boundPromise;
|
844
|
+
}
|
845
|
+
}
|
846
|
+
}
|
847
|
+
|
848
|
+
function registerServerReference(proxy, reference, encodeFormAction) {
|
849
|
+
// Expose encoder for use by SSR, as well as a special bind that can be used to
|
850
|
+
// keep server capabilities.
|
851
|
+
{
|
852
|
+
// Only expose this in builds that would actually use it. Not needed on the client.
|
853
|
+
const $$FORM_ACTION = encodeFormAction === undefined ? defaultEncodeFormAction : function (identifierPrefix) {
|
854
|
+
return customEncodeFormAction(this, identifierPrefix, encodeFormAction);
|
855
|
+
};
|
856
|
+
Object.defineProperties(proxy, {
|
857
|
+
$$FORM_ACTION: {
|
858
|
+
value: $$FORM_ACTION
|
859
|
+
},
|
860
|
+
$$IS_SIGNATURE_EQUAL: {
|
861
|
+
value: isSignatureEqual
|
862
|
+
},
|
863
|
+
bind: {
|
864
|
+
value: bind
|
865
|
+
}
|
866
|
+
});
|
867
|
+
}
|
868
|
+
|
869
|
+
knownServerReferences.set(proxy, reference);
|
870
|
+
} // $FlowFixMe[method-unbinding]
|
871
|
+
|
872
|
+
const FunctionBind = Function.prototype.bind; // $FlowFixMe[method-unbinding]
|
873
|
+
|
874
|
+
const ArraySlice = Array.prototype.slice;
|
875
|
+
|
876
|
+
function bind() {
|
877
|
+
// $FlowFixMe[unsupported-syntax]
|
878
|
+
const newFn = FunctionBind.apply(this, arguments);
|
879
|
+
const reference = knownServerReferences.get(this);
|
880
|
+
|
881
|
+
if (reference) {
|
882
|
+
|
883
|
+
const args = ArraySlice.call(arguments, 1);
|
884
|
+
let boundPromise = null;
|
885
|
+
|
886
|
+
if (reference.bound !== null) {
|
887
|
+
boundPromise = Promise.resolve(reference.bound).then(boundArgs => boundArgs.concat(args));
|
888
|
+
} else {
|
889
|
+
boundPromise = Promise.resolve(args);
|
890
|
+
} // Expose encoder for use by SSR, as well as a special bind that can be used to
|
891
|
+
// keep server capabilities.
|
892
|
+
|
893
|
+
|
894
|
+
{
|
895
|
+
// Only expose this in builds that would actually use it. Not needed on the client.
|
896
|
+
Object.defineProperties(newFn, {
|
897
|
+
$$FORM_ACTION: {
|
898
|
+
value: this.$$FORM_ACTION
|
899
|
+
},
|
900
|
+
$$IS_SIGNATURE_EQUAL: {
|
901
|
+
value: isSignatureEqual
|
902
|
+
},
|
903
|
+
bind: {
|
904
|
+
value: bind
|
905
|
+
}
|
906
|
+
});
|
907
|
+
}
|
908
|
+
|
909
|
+
knownServerReferences.set(newFn, {
|
910
|
+
id: reference.id,
|
911
|
+
bound: boundPromise
|
912
|
+
});
|
913
|
+
}
|
914
|
+
|
915
|
+
return newFn;
|
916
|
+
}
|
917
|
+
|
918
|
+
function createServerReference$1(id, callServer, encodeFormAction) {
|
919
|
+
const proxy = function () {
|
920
|
+
// $FlowFixMe[method-unbinding]
|
921
|
+
const args = Array.prototype.slice.call(arguments);
|
922
|
+
return callServer(id, args);
|
923
|
+
};
|
924
|
+
|
925
|
+
registerServerReference(proxy, {
|
926
|
+
id,
|
927
|
+
bound: null
|
928
|
+
}, encodeFormAction);
|
929
|
+
return proxy;
|
930
|
+
}
|
931
|
+
|
932
|
+
const ROW_ID = 0;
|
933
|
+
const ROW_TAG = 1;
|
934
|
+
const ROW_LENGTH = 2;
|
935
|
+
const ROW_CHUNK_BY_NEWLINE = 3;
|
936
|
+
const ROW_CHUNK_BY_LENGTH = 4;
|
937
|
+
const PENDING = 'pending';
|
938
|
+
const BLOCKED = 'blocked';
|
939
|
+
const CYCLIC = 'cyclic';
|
940
|
+
const RESOLVED_MODEL = 'resolved_model';
|
941
|
+
const RESOLVED_MODULE = 'resolved_module';
|
942
|
+
const INITIALIZED = 'fulfilled';
|
943
|
+
const ERRORED = 'rejected'; // $FlowFixMe[missing-this-annot]
|
944
|
+
|
945
|
+
function Chunk(status, value, reason, response) {
|
946
|
+
this.status = status;
|
947
|
+
this.value = value;
|
948
|
+
this.reason = reason;
|
949
|
+
this._response = response;
|
950
|
+
} // We subclass Promise.prototype so that we get other methods like .catch
|
951
|
+
|
952
|
+
|
953
|
+
Chunk.prototype = Object.create(Promise.prototype); // TODO: This doesn't return a new Promise chain unlike the real .then
|
954
|
+
|
955
|
+
Chunk.prototype.then = function (resolve, reject) {
|
956
|
+
const chunk = this; // If we have resolved content, we try to initialize it first which
|
957
|
+
// might put us back into one of the other states.
|
958
|
+
|
959
|
+
switch (chunk.status) {
|
960
|
+
case RESOLVED_MODEL:
|
961
|
+
initializeModelChunk(chunk);
|
962
|
+
break;
|
963
|
+
|
964
|
+
case RESOLVED_MODULE:
|
965
|
+
initializeModuleChunk(chunk);
|
966
|
+
break;
|
967
|
+
} // The status might have changed after initialization.
|
968
|
+
|
969
|
+
|
970
|
+
switch (chunk.status) {
|
971
|
+
case INITIALIZED:
|
972
|
+
resolve(chunk.value);
|
973
|
+
break;
|
974
|
+
|
975
|
+
case PENDING:
|
976
|
+
case BLOCKED:
|
977
|
+
case CYCLIC:
|
978
|
+
if (resolve) {
|
979
|
+
if (chunk.value === null) {
|
980
|
+
chunk.value = [];
|
981
|
+
}
|
982
|
+
|
983
|
+
chunk.value.push(resolve);
|
984
|
+
}
|
985
|
+
|
986
|
+
if (reject) {
|
987
|
+
if (chunk.reason === null) {
|
988
|
+
chunk.reason = [];
|
989
|
+
}
|
990
|
+
|
991
|
+
chunk.reason.push(reject);
|
992
|
+
}
|
993
|
+
|
994
|
+
break;
|
995
|
+
|
996
|
+
default:
|
997
|
+
reject(chunk.reason);
|
998
|
+
break;
|
999
|
+
}
|
1000
|
+
};
|
1001
|
+
|
1002
|
+
function readChunk(chunk) {
|
1003
|
+
// If we have resolved content, we try to initialize it first which
|
1004
|
+
// might put us back into one of the other states.
|
1005
|
+
switch (chunk.status) {
|
1006
|
+
case RESOLVED_MODEL:
|
1007
|
+
initializeModelChunk(chunk);
|
1008
|
+
break;
|
1009
|
+
|
1010
|
+
case RESOLVED_MODULE:
|
1011
|
+
initializeModuleChunk(chunk);
|
1012
|
+
break;
|
1013
|
+
} // The status might have changed after initialization.
|
1014
|
+
|
1015
|
+
|
1016
|
+
switch (chunk.status) {
|
1017
|
+
case INITIALIZED:
|
1018
|
+
return chunk.value;
|
1019
|
+
|
1020
|
+
case PENDING:
|
1021
|
+
case BLOCKED:
|
1022
|
+
case CYCLIC:
|
1023
|
+
// eslint-disable-next-line no-throw-literal
|
1024
|
+
throw chunk;
|
1025
|
+
|
1026
|
+
default:
|
1027
|
+
throw chunk.reason;
|
1028
|
+
}
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
function getRoot(response) {
|
1032
|
+
const chunk = getChunk(response, 0);
|
1033
|
+
return chunk;
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
function createPendingChunk(response) {
|
1037
|
+
// $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
|
1038
|
+
return new Chunk(PENDING, null, null, response);
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
function createBlockedChunk(response) {
|
1042
|
+
// $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
|
1043
|
+
return new Chunk(BLOCKED, null, null, response);
|
1044
|
+
}
|
1045
|
+
|
1046
|
+
function createErrorChunk(response, error) {
|
1047
|
+
// $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
|
1048
|
+
return new Chunk(ERRORED, null, error, response);
|
1049
|
+
}
|
1050
|
+
|
1051
|
+
function wakeChunk(listeners, value) {
|
1052
|
+
for (let i = 0; i < listeners.length; i++) {
|
1053
|
+
const listener = listeners[i];
|
1054
|
+
listener(value);
|
1055
|
+
}
|
1056
|
+
}
|
1057
|
+
|
1058
|
+
function wakeChunkIfInitialized(chunk, resolveListeners, rejectListeners) {
|
1059
|
+
switch (chunk.status) {
|
1060
|
+
case INITIALIZED:
|
1061
|
+
wakeChunk(resolveListeners, chunk.value);
|
1062
|
+
break;
|
1063
|
+
|
1064
|
+
case PENDING:
|
1065
|
+
case BLOCKED:
|
1066
|
+
case CYCLIC:
|
1067
|
+
chunk.value = resolveListeners;
|
1068
|
+
chunk.reason = rejectListeners;
|
1069
|
+
break;
|
1070
|
+
|
1071
|
+
case ERRORED:
|
1072
|
+
if (rejectListeners) {
|
1073
|
+
wakeChunk(rejectListeners, chunk.reason);
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
break;
|
1077
|
+
}
|
1078
|
+
}
|
1079
|
+
|
1080
|
+
function triggerErrorOnChunk(chunk, error) {
|
1081
|
+
if (chunk.status !== PENDING && chunk.status !== BLOCKED) {
|
1082
|
+
// We already resolved. We didn't expect to see this.
|
1083
|
+
return;
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
const listeners = chunk.reason;
|
1087
|
+
const erroredChunk = chunk;
|
1088
|
+
erroredChunk.status = ERRORED;
|
1089
|
+
erroredChunk.reason = error;
|
1090
|
+
|
1091
|
+
if (listeners !== null) {
|
1092
|
+
wakeChunk(listeners, error);
|
1093
|
+
}
|
1094
|
+
}
|
1095
|
+
|
1096
|
+
function createResolvedModelChunk(response, value) {
|
1097
|
+
// $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
|
1098
|
+
return new Chunk(RESOLVED_MODEL, value, null, response);
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
function createResolvedModuleChunk(response, value) {
|
1102
|
+
// $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
|
1103
|
+
return new Chunk(RESOLVED_MODULE, value, null, response);
|
1104
|
+
}
|
1105
|
+
|
1106
|
+
function createInitializedTextChunk(response, value) {
|
1107
|
+
// $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
|
1108
|
+
return new Chunk(INITIALIZED, value, null, response);
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
function resolveModelChunk(chunk, value) {
|
1112
|
+
if (chunk.status !== PENDING) {
|
1113
|
+
// We already resolved. We didn't expect to see this.
|
1114
|
+
return;
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
const resolveListeners = chunk.value;
|
1118
|
+
const rejectListeners = chunk.reason;
|
1119
|
+
const resolvedChunk = chunk;
|
1120
|
+
resolvedChunk.status = RESOLVED_MODEL;
|
1121
|
+
resolvedChunk.value = value;
|
1122
|
+
|
1123
|
+
if (resolveListeners !== null) {
|
1124
|
+
// This is unfortunate that we're reading this eagerly if
|
1125
|
+
// we already have listeners attached since they might no
|
1126
|
+
// longer be rendered or might not be the highest pri.
|
1127
|
+
initializeModelChunk(resolvedChunk); // The status might have changed after initialization.
|
1128
|
+
|
1129
|
+
wakeChunkIfInitialized(chunk, resolveListeners, rejectListeners);
|
1130
|
+
}
|
1131
|
+
}
|
1132
|
+
|
1133
|
+
function resolveModuleChunk(chunk, value) {
|
1134
|
+
if (chunk.status !== PENDING && chunk.status !== BLOCKED) {
|
1135
|
+
// We already resolved. We didn't expect to see this.
|
1136
|
+
return;
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
const resolveListeners = chunk.value;
|
1140
|
+
const rejectListeners = chunk.reason;
|
1141
|
+
const resolvedChunk = chunk;
|
1142
|
+
resolvedChunk.status = RESOLVED_MODULE;
|
1143
|
+
resolvedChunk.value = value;
|
1144
|
+
|
1145
|
+
if (resolveListeners !== null) {
|
1146
|
+
initializeModuleChunk(resolvedChunk);
|
1147
|
+
wakeChunkIfInitialized(chunk, resolveListeners, rejectListeners);
|
1148
|
+
}
|
1149
|
+
}
|
1150
|
+
|
1151
|
+
let initializingChunk = null;
|
1152
|
+
let initializingChunkBlockedModel = null;
|
1153
|
+
|
1154
|
+
function initializeModelChunk(chunk) {
|
1155
|
+
const prevChunk = initializingChunk;
|
1156
|
+
const prevBlocked = initializingChunkBlockedModel;
|
1157
|
+
initializingChunk = chunk;
|
1158
|
+
initializingChunkBlockedModel = null;
|
1159
|
+
const resolvedModel = chunk.value; // We go to the CYCLIC state until we've fully resolved this.
|
1160
|
+
// We do this before parsing in case we try to initialize the same chunk
|
1161
|
+
// while parsing the model. Such as in a cyclic reference.
|
1162
|
+
|
1163
|
+
const cyclicChunk = chunk;
|
1164
|
+
cyclicChunk.status = CYCLIC;
|
1165
|
+
cyclicChunk.value = null;
|
1166
|
+
cyclicChunk.reason = null;
|
1167
|
+
|
1168
|
+
try {
|
1169
|
+
const value = parseModel(chunk._response, resolvedModel);
|
1170
|
+
|
1171
|
+
if (initializingChunkBlockedModel !== null && initializingChunkBlockedModel.deps > 0) {
|
1172
|
+
initializingChunkBlockedModel.value = value; // We discovered new dependencies on modules that are not yet resolved.
|
1173
|
+
// We have to go the BLOCKED state until they're resolved.
|
1174
|
+
|
1175
|
+
const blockedChunk = chunk;
|
1176
|
+
blockedChunk.status = BLOCKED;
|
1177
|
+
blockedChunk.value = null;
|
1178
|
+
blockedChunk.reason = null;
|
1179
|
+
} else {
|
1180
|
+
const resolveListeners = cyclicChunk.value;
|
1181
|
+
const initializedChunk = chunk;
|
1182
|
+
initializedChunk.status = INITIALIZED;
|
1183
|
+
initializedChunk.value = value;
|
1184
|
+
|
1185
|
+
if (resolveListeners !== null) {
|
1186
|
+
wakeChunk(resolveListeners, value);
|
1187
|
+
}
|
1188
|
+
}
|
1189
|
+
} catch (error) {
|
1190
|
+
const erroredChunk = chunk;
|
1191
|
+
erroredChunk.status = ERRORED;
|
1192
|
+
erroredChunk.reason = error;
|
1193
|
+
} finally {
|
1194
|
+
initializingChunk = prevChunk;
|
1195
|
+
initializingChunkBlockedModel = prevBlocked;
|
1196
|
+
}
|
1197
|
+
}
|
1198
|
+
|
1199
|
+
function initializeModuleChunk(chunk) {
|
1200
|
+
try {
|
1201
|
+
const value = requireModule(chunk.value);
|
1202
|
+
const initializedChunk = chunk;
|
1203
|
+
initializedChunk.status = INITIALIZED;
|
1204
|
+
initializedChunk.value = value;
|
1205
|
+
} catch (error) {
|
1206
|
+
const erroredChunk = chunk;
|
1207
|
+
erroredChunk.status = ERRORED;
|
1208
|
+
erroredChunk.reason = error;
|
1209
|
+
}
|
1210
|
+
} // Report that any missing chunks in the model is now going to throw this
|
1211
|
+
// error upon read. Also notify any pending promises.
|
1212
|
+
|
1213
|
+
|
1214
|
+
function reportGlobalError(response, error) {
|
1215
|
+
response._chunks.forEach(chunk => {
|
1216
|
+
// If this chunk was already resolved or errored, it won't
|
1217
|
+
// trigger an error but if it wasn't then we need to
|
1218
|
+
// because we won't be getting any new data to resolve it.
|
1219
|
+
if (chunk.status === PENDING) {
|
1220
|
+
triggerErrorOnChunk(chunk, error);
|
1221
|
+
}
|
1222
|
+
});
|
1223
|
+
}
|
1224
|
+
|
1225
|
+
function createElement(type, key, props) {
|
1226
|
+
let element;
|
1227
|
+
|
1228
|
+
{
|
1229
|
+
element = {
|
1230
|
+
// This tag allows us to uniquely identify this as a React Element
|
1231
|
+
$$typeof: REACT_ELEMENT_TYPE,
|
1232
|
+
type,
|
1233
|
+
key,
|
1234
|
+
ref: null,
|
1235
|
+
props,
|
1236
|
+
// Record the component responsible for creating this element.
|
1237
|
+
_owner: null
|
1238
|
+
};
|
1239
|
+
}
|
1240
|
+
|
1241
|
+
return element;
|
1242
|
+
}
|
1243
|
+
|
1244
|
+
function createLazyChunkWrapper(chunk) {
|
1245
|
+
const lazyType = {
|
1246
|
+
$$typeof: REACT_LAZY_TYPE,
|
1247
|
+
_payload: chunk,
|
1248
|
+
_init: readChunk
|
1249
|
+
};
|
1250
|
+
|
1251
|
+
return lazyType;
|
1252
|
+
}
|
1253
|
+
|
1254
|
+
function getChunk(response, id) {
|
1255
|
+
const chunks = response._chunks;
|
1256
|
+
let chunk = chunks.get(id);
|
1257
|
+
|
1258
|
+
if (!chunk) {
|
1259
|
+
chunk = createPendingChunk(response);
|
1260
|
+
chunks.set(id, chunk);
|
1261
|
+
}
|
1262
|
+
|
1263
|
+
return chunk;
|
1264
|
+
}
|
1265
|
+
|
1266
|
+
function createModelResolver(chunk, parentObject, key, cyclic) {
|
1267
|
+
let blocked;
|
1268
|
+
|
1269
|
+
if (initializingChunkBlockedModel) {
|
1270
|
+
blocked = initializingChunkBlockedModel;
|
1271
|
+
|
1272
|
+
if (!cyclic) {
|
1273
|
+
blocked.deps++;
|
1274
|
+
}
|
1275
|
+
} else {
|
1276
|
+
blocked = initializingChunkBlockedModel = {
|
1277
|
+
deps: cyclic ? 0 : 1,
|
1278
|
+
value: null
|
1279
|
+
};
|
1280
|
+
}
|
1281
|
+
|
1282
|
+
return value => {
|
1283
|
+
parentObject[key] = value;
|
1284
|
+
blocked.deps--;
|
1285
|
+
|
1286
|
+
if (blocked.deps === 0) {
|
1287
|
+
if (chunk.status !== BLOCKED) {
|
1288
|
+
return;
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
const resolveListeners = chunk.value;
|
1292
|
+
const initializedChunk = chunk;
|
1293
|
+
initializedChunk.status = INITIALIZED;
|
1294
|
+
initializedChunk.value = blocked.value;
|
1295
|
+
|
1296
|
+
if (resolveListeners !== null) {
|
1297
|
+
wakeChunk(resolveListeners, blocked.value);
|
1298
|
+
}
|
1299
|
+
}
|
1300
|
+
};
|
1301
|
+
}
|
1302
|
+
|
1303
|
+
function createModelReject(chunk) {
|
1304
|
+
return error => triggerErrorOnChunk(chunk, error);
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
function createServerReferenceProxy(response, metaData) {
|
1308
|
+
const callServer = response._callServer;
|
1309
|
+
|
1310
|
+
const proxy = function () {
|
1311
|
+
// $FlowFixMe[method-unbinding]
|
1312
|
+
const args = Array.prototype.slice.call(arguments);
|
1313
|
+
const p = metaData.bound;
|
1314
|
+
|
1315
|
+
if (!p) {
|
1316
|
+
return callServer(metaData.id, args);
|
1317
|
+
}
|
1318
|
+
|
1319
|
+
if (p.status === INITIALIZED) {
|
1320
|
+
const bound = p.value;
|
1321
|
+
return callServer(metaData.id, bound.concat(args));
|
1322
|
+
} // Since this is a fake Promise whose .then doesn't chain, we have to wrap it.
|
1323
|
+
// TODO: Remove the wrapper once that's fixed.
|
1324
|
+
|
1325
|
+
|
1326
|
+
return Promise.resolve(p).then(function (bound) {
|
1327
|
+
return callServer(metaData.id, bound.concat(args));
|
1328
|
+
});
|
1329
|
+
};
|
1330
|
+
|
1331
|
+
registerServerReference(proxy, metaData, response._encodeFormAction);
|
1332
|
+
return proxy;
|
1333
|
+
}
|
1334
|
+
|
1335
|
+
function getOutlinedModel(response, id) {
|
1336
|
+
const chunk = getChunk(response, id);
|
1337
|
+
|
1338
|
+
switch (chunk.status) {
|
1339
|
+
case RESOLVED_MODEL:
|
1340
|
+
initializeModelChunk(chunk);
|
1341
|
+
break;
|
1342
|
+
} // The status might have changed after initialization.
|
1343
|
+
|
1344
|
+
|
1345
|
+
switch (chunk.status) {
|
1346
|
+
case INITIALIZED:
|
1347
|
+
{
|
1348
|
+
return chunk.value;
|
1349
|
+
}
|
1350
|
+
// We always encode it first in the stream so it won't be pending.
|
1351
|
+
|
1352
|
+
default:
|
1353
|
+
throw chunk.reason;
|
1354
|
+
}
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
function parseModelString(response, parentObject, key, value) {
|
1358
|
+
if (value[0] === '$') {
|
1359
|
+
if (value === '$') {
|
1360
|
+
// A very common symbol.
|
1361
|
+
return REACT_ELEMENT_TYPE;
|
1362
|
+
}
|
1363
|
+
|
1364
|
+
switch (value[1]) {
|
1365
|
+
case '$':
|
1366
|
+
{
|
1367
|
+
// This was an escaped string value.
|
1368
|
+
return value.slice(1);
|
1369
|
+
}
|
1370
|
+
|
1371
|
+
case 'L':
|
1372
|
+
{
|
1373
|
+
// Lazy node
|
1374
|
+
const id = parseInt(value.slice(2), 16);
|
1375
|
+
const chunk = getChunk(response, id); // We create a React.lazy wrapper around any lazy values.
|
1376
|
+
// When passed into React, we'll know how to suspend on this.
|
1377
|
+
|
1378
|
+
return createLazyChunkWrapper(chunk);
|
1379
|
+
}
|
1380
|
+
|
1381
|
+
case '@':
|
1382
|
+
{
|
1383
|
+
// Promise
|
1384
|
+
if (value.length === 2) {
|
1385
|
+
// Infinite promise that never resolves.
|
1386
|
+
return new Promise(() => {});
|
1387
|
+
}
|
1388
|
+
|
1389
|
+
const id = parseInt(value.slice(2), 16);
|
1390
|
+
const chunk = getChunk(response, id);
|
1391
|
+
return chunk;
|
1392
|
+
}
|
1393
|
+
|
1394
|
+
case 'S':
|
1395
|
+
{
|
1396
|
+
// Symbol
|
1397
|
+
return Symbol.for(value.slice(2));
|
1398
|
+
}
|
1399
|
+
|
1400
|
+
case 'F':
|
1401
|
+
{
|
1402
|
+
// Server Reference
|
1403
|
+
const id = parseInt(value.slice(2), 16);
|
1404
|
+
const metadata = getOutlinedModel(response, id);
|
1405
|
+
return createServerReferenceProxy(response, metadata);
|
1406
|
+
}
|
1407
|
+
|
1408
|
+
case 'T':
|
1409
|
+
{
|
1410
|
+
// Temporary Reference
|
1411
|
+
const id = parseInt(value.slice(2), 16);
|
1412
|
+
const temporaryReferences = response._tempRefs;
|
1413
|
+
|
1414
|
+
if (temporaryReferences == null) {
|
1415
|
+
throw new Error('Missing a temporary reference set but the RSC response returned a temporary reference. ' + 'Pass a temporaryReference option with the set that was used with the reply.');
|
1416
|
+
}
|
1417
|
+
|
1418
|
+
return readTemporaryReference(temporaryReferences, id);
|
1419
|
+
}
|
1420
|
+
|
1421
|
+
case 'Q':
|
1422
|
+
{
|
1423
|
+
// Map
|
1424
|
+
const id = parseInt(value.slice(2), 16);
|
1425
|
+
const data = getOutlinedModel(response, id);
|
1426
|
+
return new Map(data);
|
1427
|
+
}
|
1428
|
+
|
1429
|
+
case 'W':
|
1430
|
+
{
|
1431
|
+
// Set
|
1432
|
+
const id = parseInt(value.slice(2), 16);
|
1433
|
+
const data = getOutlinedModel(response, id);
|
1434
|
+
return new Set(data);
|
1435
|
+
}
|
1436
|
+
|
1437
|
+
case 'I':
|
1438
|
+
{
|
1439
|
+
// $Infinity
|
1440
|
+
return Infinity;
|
1441
|
+
}
|
1442
|
+
|
1443
|
+
case '-':
|
1444
|
+
{
|
1445
|
+
// $-0 or $-Infinity
|
1446
|
+
if (value === '$-0') {
|
1447
|
+
return -0;
|
1448
|
+
} else {
|
1449
|
+
return -Infinity;
|
1450
|
+
}
|
1451
|
+
}
|
1452
|
+
|
1453
|
+
case 'N':
|
1454
|
+
{
|
1455
|
+
// $NaN
|
1456
|
+
return NaN;
|
1457
|
+
}
|
1458
|
+
|
1459
|
+
case 'u':
|
1460
|
+
{
|
1461
|
+
// matches "$undefined"
|
1462
|
+
// Special encoding for `undefined` which can't be serialized as JSON otherwise.
|
1463
|
+
return undefined;
|
1464
|
+
}
|
1465
|
+
|
1466
|
+
case 'D':
|
1467
|
+
{
|
1468
|
+
// Date
|
1469
|
+
return new Date(Date.parse(value.slice(2)));
|
1470
|
+
}
|
1471
|
+
|
1472
|
+
case 'n':
|
1473
|
+
{
|
1474
|
+
// BigInt
|
1475
|
+
return BigInt(value.slice(2));
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
case 'E':
|
1479
|
+
|
1480
|
+
default:
|
1481
|
+
{
|
1482
|
+
// We assume that anything else is a reference ID.
|
1483
|
+
const id = parseInt(value.slice(1), 16);
|
1484
|
+
const chunk = getChunk(response, id);
|
1485
|
+
|
1486
|
+
switch (chunk.status) {
|
1487
|
+
case RESOLVED_MODEL:
|
1488
|
+
initializeModelChunk(chunk);
|
1489
|
+
break;
|
1490
|
+
|
1491
|
+
case RESOLVED_MODULE:
|
1492
|
+
initializeModuleChunk(chunk);
|
1493
|
+
break;
|
1494
|
+
} // The status might have changed after initialization.
|
1495
|
+
|
1496
|
+
|
1497
|
+
switch (chunk.status) {
|
1498
|
+
case INITIALIZED:
|
1499
|
+
const chunkValue = chunk.value;
|
1500
|
+
|
1501
|
+
return chunkValue;
|
1502
|
+
|
1503
|
+
case PENDING:
|
1504
|
+
case BLOCKED:
|
1505
|
+
case CYCLIC:
|
1506
|
+
const parentChunk = initializingChunk;
|
1507
|
+
chunk.then(createModelResolver(parentChunk, parentObject, key, chunk.status === CYCLIC), createModelReject(parentChunk));
|
1508
|
+
return null;
|
1509
|
+
|
1510
|
+
default:
|
1511
|
+
throw chunk.reason;
|
1512
|
+
}
|
1513
|
+
}
|
1514
|
+
}
|
1515
|
+
}
|
1516
|
+
|
1517
|
+
return value;
|
1518
|
+
}
|
1519
|
+
|
1520
|
+
function parseModelTuple(response, value) {
|
1521
|
+
const tuple = value;
|
1522
|
+
|
1523
|
+
if (tuple[0] === REACT_ELEMENT_TYPE) {
|
1524
|
+
// TODO: Consider having React just directly accept these arrays as elements.
|
1525
|
+
// Or even change the ReactElement type to be an array.
|
1526
|
+
return createElement(tuple[1], tuple[2], tuple[3]);
|
1527
|
+
}
|
1528
|
+
|
1529
|
+
return value;
|
1530
|
+
}
|
1531
|
+
|
1532
|
+
function missingCall() {
|
1533
|
+
throw new Error('Trying to call a function from "use server" but the callServer option ' + 'was not implemented in your router runtime.');
|
1534
|
+
}
|
1535
|
+
|
1536
|
+
function createResponse(bundlerConfig, moduleLoading, callServer, encodeFormAction, nonce, temporaryReferences) {
|
1537
|
+
const chunks = new Map();
|
1538
|
+
const response = {
|
1539
|
+
_bundlerConfig: bundlerConfig,
|
1540
|
+
_moduleLoading: moduleLoading,
|
1541
|
+
_callServer: callServer !== undefined ? callServer : missingCall,
|
1542
|
+
_encodeFormAction: encodeFormAction,
|
1543
|
+
_nonce: nonce,
|
1544
|
+
_chunks: chunks,
|
1545
|
+
_stringDecoder: createStringDecoder(),
|
1546
|
+
_fromJSON: null,
|
1547
|
+
_rowState: 0,
|
1548
|
+
_rowID: 0,
|
1549
|
+
_rowTag: 0,
|
1550
|
+
_rowLength: 0,
|
1551
|
+
_buffer: [],
|
1552
|
+
_tempRefs: temporaryReferences
|
1553
|
+
}; // Don't inline this call because it causes closure to outline the call above.
|
1554
|
+
|
1555
|
+
response._fromJSON = createFromJSONCallback(response);
|
1556
|
+
return response;
|
1557
|
+
}
|
1558
|
+
|
1559
|
+
function resolveModel(response, id, model) {
|
1560
|
+
const chunks = response._chunks;
|
1561
|
+
const chunk = chunks.get(id);
|
1562
|
+
|
1563
|
+
if (!chunk) {
|
1564
|
+
chunks.set(id, createResolvedModelChunk(response, model));
|
1565
|
+
} else {
|
1566
|
+
resolveModelChunk(chunk, model);
|
1567
|
+
}
|
1568
|
+
}
|
1569
|
+
|
1570
|
+
function resolveText(response, id, text) {
|
1571
|
+
const chunks = response._chunks; // We assume that we always reference large strings after they've been
|
1572
|
+
// emitted.
|
1573
|
+
|
1574
|
+
chunks.set(id, createInitializedTextChunk(response, text));
|
1575
|
+
}
|
1576
|
+
|
1577
|
+
function resolveModule(response, id, model) {
|
1578
|
+
const chunks = response._chunks;
|
1579
|
+
const chunk = chunks.get(id);
|
1580
|
+
const clientReferenceMetadata = parseModel(response, model);
|
1581
|
+
const clientReference = resolveClientReference(response._bundlerConfig, clientReferenceMetadata);
|
1582
|
+
prepareDestinationForModule(response._moduleLoading, response._nonce, clientReferenceMetadata); // TODO: Add an option to encode modules that are lazy loaded.
|
1583
|
+
// For now we preload all modules as early as possible since it's likely
|
1584
|
+
// that we'll need them.
|
1585
|
+
|
1586
|
+
const promise = preloadModule(clientReference);
|
1587
|
+
|
1588
|
+
if (promise) {
|
1589
|
+
let blockedChunk;
|
1590
|
+
|
1591
|
+
if (!chunk) {
|
1592
|
+
// Technically, we should just treat promise as the chunk in this
|
1593
|
+
// case. Because it'll just behave as any other promise.
|
1594
|
+
blockedChunk = createBlockedChunk(response);
|
1595
|
+
chunks.set(id, blockedChunk);
|
1596
|
+
} else {
|
1597
|
+
// This can't actually happen because we don't have any forward
|
1598
|
+
// references to modules.
|
1599
|
+
blockedChunk = chunk;
|
1600
|
+
blockedChunk.status = BLOCKED;
|
1601
|
+
}
|
1602
|
+
|
1603
|
+
promise.then(() => resolveModuleChunk(blockedChunk, clientReference), error => triggerErrorOnChunk(blockedChunk, error));
|
1604
|
+
} else {
|
1605
|
+
if (!chunk) {
|
1606
|
+
chunks.set(id, createResolvedModuleChunk(response, clientReference));
|
1607
|
+
} else {
|
1608
|
+
// This can't actually happen because we don't have any forward
|
1609
|
+
// references to modules.
|
1610
|
+
resolveModuleChunk(chunk, clientReference);
|
1611
|
+
}
|
1612
|
+
}
|
1613
|
+
}
|
1614
|
+
|
1615
|
+
function resolveErrorProd(response, id, digest) {
|
1616
|
+
|
1617
|
+
const error = new Error('An error occurred in the Server Components render. The specific message is omitted in production' + ' builds to avoid leaking sensitive details. A digest property is included on this error instance which' + ' may provide additional details about the nature of the error.');
|
1618
|
+
error.stack = 'Error: ' + error.message;
|
1619
|
+
error.digest = digest;
|
1620
|
+
const errorWithDigest = error;
|
1621
|
+
const chunks = response._chunks;
|
1622
|
+
const chunk = chunks.get(id);
|
1623
|
+
|
1624
|
+
if (!chunk) {
|
1625
|
+
chunks.set(id, createErrorChunk(response, errorWithDigest));
|
1626
|
+
} else {
|
1627
|
+
triggerErrorOnChunk(chunk, errorWithDigest);
|
1628
|
+
}
|
1629
|
+
}
|
1630
|
+
|
1631
|
+
function resolveHint(response, code, model) {
|
1632
|
+
const hintModel = parseModel(response, model);
|
1633
|
+
dispatchHint(code, hintModel);
|
1634
|
+
}
|
1635
|
+
|
1636
|
+
function processFullRow(response, id, tag, buffer, chunk) {
|
1637
|
+
|
1638
|
+
const stringDecoder = response._stringDecoder;
|
1639
|
+
let row = '';
|
1640
|
+
|
1641
|
+
for (let i = 0; i < buffer.length; i++) {
|
1642
|
+
row += readPartialStringChunk(stringDecoder, buffer[i]);
|
1643
|
+
}
|
1644
|
+
|
1645
|
+
row += readFinalStringChunk(stringDecoder, chunk);
|
1646
|
+
|
1647
|
+
switch (tag) {
|
1648
|
+
case 73
|
1649
|
+
/* "I" */
|
1650
|
+
:
|
1651
|
+
{
|
1652
|
+
resolveModule(response, id, row);
|
1653
|
+
return;
|
1654
|
+
}
|
1655
|
+
|
1656
|
+
case 72
|
1657
|
+
/* "H" */
|
1658
|
+
:
|
1659
|
+
{
|
1660
|
+
const code = row[0];
|
1661
|
+
resolveHint(response, code, row.slice(1));
|
1662
|
+
return;
|
1663
|
+
}
|
1664
|
+
|
1665
|
+
case 69
|
1666
|
+
/* "E" */
|
1667
|
+
:
|
1668
|
+
{
|
1669
|
+
const errorInfo = JSON.parse(row);
|
1670
|
+
|
1671
|
+
{
|
1672
|
+
resolveErrorProd(response, id, errorInfo.digest);
|
1673
|
+
}
|
1674
|
+
|
1675
|
+
return;
|
1676
|
+
}
|
1677
|
+
|
1678
|
+
case 84
|
1679
|
+
/* "T" */
|
1680
|
+
:
|
1681
|
+
{
|
1682
|
+
resolveText(response, id, row);
|
1683
|
+
return;
|
1684
|
+
}
|
1685
|
+
|
1686
|
+
case 68
|
1687
|
+
/* "D" */
|
1688
|
+
:
|
1689
|
+
|
1690
|
+
case 87
|
1691
|
+
/* "W" */
|
1692
|
+
:
|
1693
|
+
{
|
1694
|
+
|
1695
|
+
throw new Error('Failed to read a RSC payload created by a development version of React ' + 'on the server while using a production version on the client. Always use ' + 'matching versions on the server and the client.');
|
1696
|
+
}
|
1697
|
+
|
1698
|
+
case 80
|
1699
|
+
/* "P" */
|
1700
|
+
:
|
1701
|
+
// Fallthrough
|
1702
|
+
|
1703
|
+
default:
|
1704
|
+
/* """ "{" "[" "t" "f" "n" "0" - "9" */
|
1705
|
+
{
|
1706
|
+
// We assume anything else is JSON.
|
1707
|
+
resolveModel(response, id, row);
|
1708
|
+
return;
|
1709
|
+
}
|
1710
|
+
}
|
1711
|
+
}
|
1712
|
+
|
1713
|
+
function processBinaryChunk(response, chunk) {
|
1714
|
+
let i = 0;
|
1715
|
+
let rowState = response._rowState;
|
1716
|
+
let rowID = response._rowID;
|
1717
|
+
let rowTag = response._rowTag;
|
1718
|
+
let rowLength = response._rowLength;
|
1719
|
+
const buffer = response._buffer;
|
1720
|
+
const chunkLength = chunk.length;
|
1721
|
+
|
1722
|
+
while (i < chunkLength) {
|
1723
|
+
let lastIdx = -1;
|
1724
|
+
|
1725
|
+
switch (rowState) {
|
1726
|
+
case ROW_ID:
|
1727
|
+
{
|
1728
|
+
const byte = chunk[i++];
|
1729
|
+
|
1730
|
+
if (byte === 58
|
1731
|
+
/* ":" */
|
1732
|
+
) {
|
1733
|
+
// Finished the rowID, next we'll parse the tag.
|
1734
|
+
rowState = ROW_TAG;
|
1735
|
+
} else {
|
1736
|
+
rowID = rowID << 4 | (byte > 96 ? byte - 87 : byte - 48);
|
1737
|
+
}
|
1738
|
+
|
1739
|
+
continue;
|
1740
|
+
}
|
1741
|
+
|
1742
|
+
case ROW_TAG:
|
1743
|
+
{
|
1744
|
+
const resolvedRowTag = chunk[i];
|
1745
|
+
|
1746
|
+
if (resolvedRowTag === 84
|
1747
|
+
/* "T" */
|
1748
|
+
|| enableBinaryFlight
|
1749
|
+
/* "V" */
|
1750
|
+
) {
|
1751
|
+
rowTag = resolvedRowTag;
|
1752
|
+
rowState = ROW_LENGTH;
|
1753
|
+
i++;
|
1754
|
+
} else if (resolvedRowTag > 64 && resolvedRowTag < 91
|
1755
|
+
/* "A"-"Z" */
|
1756
|
+
) {
|
1757
|
+
rowTag = resolvedRowTag;
|
1758
|
+
rowState = ROW_CHUNK_BY_NEWLINE;
|
1759
|
+
i++;
|
1760
|
+
} else {
|
1761
|
+
rowTag = 0;
|
1762
|
+
rowState = ROW_CHUNK_BY_NEWLINE; // This was an unknown tag so it was probably part of the data.
|
1763
|
+
}
|
1764
|
+
|
1765
|
+
continue;
|
1766
|
+
}
|
1767
|
+
|
1768
|
+
case ROW_LENGTH:
|
1769
|
+
{
|
1770
|
+
const byte = chunk[i++];
|
1771
|
+
|
1772
|
+
if (byte === 44
|
1773
|
+
/* "," */
|
1774
|
+
) {
|
1775
|
+
// Finished the rowLength, next we'll buffer up to that length.
|
1776
|
+
rowState = ROW_CHUNK_BY_LENGTH;
|
1777
|
+
} else {
|
1778
|
+
rowLength = rowLength << 4 | (byte > 96 ? byte - 87 : byte - 48);
|
1779
|
+
}
|
1780
|
+
|
1781
|
+
continue;
|
1782
|
+
}
|
1783
|
+
|
1784
|
+
case ROW_CHUNK_BY_NEWLINE:
|
1785
|
+
{
|
1786
|
+
// We're looking for a newline
|
1787
|
+
lastIdx = chunk.indexOf(10
|
1788
|
+
/* "\n" */
|
1789
|
+
, i);
|
1790
|
+
break;
|
1791
|
+
}
|
1792
|
+
|
1793
|
+
case ROW_CHUNK_BY_LENGTH:
|
1794
|
+
{
|
1795
|
+
// We're looking for the remaining byte length
|
1796
|
+
lastIdx = i + rowLength;
|
1797
|
+
|
1798
|
+
if (lastIdx > chunk.length) {
|
1799
|
+
lastIdx = -1;
|
1800
|
+
}
|
1801
|
+
|
1802
|
+
break;
|
1803
|
+
}
|
1804
|
+
}
|
1805
|
+
|
1806
|
+
const offset = chunk.byteOffset + i;
|
1807
|
+
|
1808
|
+
if (lastIdx > -1) {
|
1809
|
+
// We found the last chunk of the row
|
1810
|
+
const length = lastIdx - i;
|
1811
|
+
const lastChunk = new Uint8Array(chunk.buffer, offset, length);
|
1812
|
+
processFullRow(response, rowID, rowTag, buffer, lastChunk); // Reset state machine for a new row
|
1813
|
+
|
1814
|
+
i = lastIdx;
|
1815
|
+
|
1816
|
+
if (rowState === ROW_CHUNK_BY_NEWLINE) {
|
1817
|
+
// If we're trailing by a newline we need to skip it.
|
1818
|
+
i++;
|
1819
|
+
}
|
1820
|
+
|
1821
|
+
rowState = ROW_ID;
|
1822
|
+
rowTag = 0;
|
1823
|
+
rowID = 0;
|
1824
|
+
rowLength = 0;
|
1825
|
+
buffer.length = 0;
|
1826
|
+
} else {
|
1827
|
+
// The rest of this row is in a future chunk. We stash the rest of the
|
1828
|
+
// current chunk until we can process the full row.
|
1829
|
+
const length = chunk.byteLength - i;
|
1830
|
+
const remainingSlice = new Uint8Array(chunk.buffer, offset, length);
|
1831
|
+
buffer.push(remainingSlice); // Update how many bytes we're still waiting for. If we're looking for
|
1832
|
+
// a newline, this doesn't hurt since we'll just ignore it.
|
1833
|
+
|
1834
|
+
rowLength -= remainingSlice.byteLength;
|
1835
|
+
break;
|
1836
|
+
}
|
1837
|
+
}
|
1838
|
+
|
1839
|
+
response._rowState = rowState;
|
1840
|
+
response._rowID = rowID;
|
1841
|
+
response._rowTag = rowTag;
|
1842
|
+
response._rowLength = rowLength;
|
1843
|
+
}
|
1844
|
+
|
1845
|
+
function parseModel(response, json) {
|
1846
|
+
return JSON.parse(json, response._fromJSON);
|
1847
|
+
}
|
1848
|
+
|
1849
|
+
function createFromJSONCallback(response) {
|
1850
|
+
// $FlowFixMe[missing-this-annot]
|
1851
|
+
return function (key, value) {
|
1852
|
+
if (typeof value === 'string') {
|
1853
|
+
// We can't use .bind here because we need the "this" value.
|
1854
|
+
return parseModelString(response, this, key, value);
|
1855
|
+
}
|
1856
|
+
|
1857
|
+
if (typeof value === 'object' && value !== null) {
|
1858
|
+
return parseModelTuple(response, value);
|
1859
|
+
}
|
1860
|
+
|
1861
|
+
return value;
|
1862
|
+
};
|
1863
|
+
}
|
1864
|
+
|
1865
|
+
function close(response) {
|
1866
|
+
// In case there are any remaining unresolved chunks, they won't
|
1867
|
+
// be resolved now. So we need to issue an error to those.
|
1868
|
+
// Ideally we should be able to early bail out if we kept a
|
1869
|
+
// ref count of pending chunks.
|
1870
|
+
reportGlobalError(response, new Error('Connection closed.'));
|
1871
|
+
}
|
1872
|
+
|
1873
|
+
function noServerCall() {
|
1874
|
+
throw new Error('Server Functions cannot be called during initial render. ' + 'This would create a fetch waterfall. Try to use a Server Component ' + 'to pass data to Client Components instead.');
|
1875
|
+
}
|
1876
|
+
|
1877
|
+
function createServerReference(id, callServer) {
|
1878
|
+
return createServerReference$1(id, noServerCall);
|
1879
|
+
}
|
1880
|
+
|
1881
|
+
function createFromNodeStream(stream, ssrManifest, options) {
|
1882
|
+
const response = createResponse(ssrManifest.moduleMap, ssrManifest.moduleLoading, noServerCall, options ? options.encodeFormAction : undefined, options && typeof options.nonce === 'string' ? options.nonce : undefined, undefined // TODO: If encodeReply is supported, this should support temporaryReferences
|
1883
|
+
);
|
1884
|
+
stream.on('data', chunk => {
|
1885
|
+
processBinaryChunk(response, chunk);
|
1886
|
+
});
|
1887
|
+
stream.on('error', error => {
|
1888
|
+
reportGlobalError(response, error);
|
1889
|
+
});
|
1890
|
+
stream.on('end', () => close(response));
|
1891
|
+
return getRoot(response);
|
1892
|
+
}
|
1893
|
+
|
1894
|
+
exports.createFromNodeStream = createFromNodeStream;
|
1895
|
+
exports.createServerReference = createServerReference;
|