894
const resolvedChunk: ResolvedModuleChunk<T> = (chunk: any);
895
resolvedChunk.status = RESOLVED_MODULE;
896
resolvedChunk.value = value;
897
+ resolvedChunk.reason = null;
898
if (__DEV__) {
899
const debugInfo = getModuleDebugInfo(value);
900
if (debugInfo !== null) {
1115
// because we won't be getting any new data to resolve it.
1116
if (chunk.status === PENDING) {
1117
triggerErrorOnChunk(response, chunk, error);
1118
+ } else if (chunk.status === INITIALIZED && chunk.reason !== null) {
1119
+ chunk.reason.error(error);
1120
}
1121
});
1122
if (__DEV__) {
1465
): void {
1466
const {handler, parentObject, key, map, path} = reference;
1467
1465
- for (let i = 1; i < path.length; i++) {
1468
+ try {
1469
+ for (let i = 1; i < path.length; i++) {
1470
+ while (
1471
+ typeof value === 'object' &&
1472
+ value !== null &&
1473
+ value.$$typeof === REACT_LAZY_TYPE
1474
+ ) {
1475
+ // We never expect to see a Lazy node on this path because we encode those as
1476
+ // separate models. This must mean that we have inserted an extra lazy node
1477
+ // e.g. to replace a blocked element. We must instead look for it inside.
1478
+ const referencedChunk: SomeChunk<any> = value._payload;
1479
+ if (referencedChunk === handler.chunk) {
1480
+ // This is a reference to the thing we're currently blocking. We can peak
1481
+ // inside of it to get the value.
1482
+ value = handler.value;
1483
+ continue;
1484
+ } else {
1485
+ switch (referencedChunk.status) {
1486
+ case RESOLVED_MODEL:
1487
+ initializeModelChunk(referencedChunk);
1488
+ break;
1489
+ case RESOLVED_MODULE:
1490
+ initializeModuleChunk(referencedChunk);
1491
+ break;
1492
+ }
1493
+ switch (referencedChunk.status) {
1494
+ case INITIALIZED: {
1495
+ value = referencedChunk.value;
1496
+ continue;
1497
+ }
1498
+ case BLOCKED: {
1499
+ // It is possible that we're blocked on our own chunk if it's a cycle.
1500
+ // Before adding the listener to the inner chunk, let's check if it would
1501
+ // result in a cycle.
1502
+ const cyclicHandler = resolveBlockedCycle(
1503
+ referencedChunk,
1504
+ reference,
1505
+ );
1506
+ if (cyclicHandler !== null) {
1507
+ // This reference points back to this chunk. We can resolve the cycle by
1508
+ // using the value from that handler.
1509
+ value = cyclicHandler.value;
1510
+ continue;
1511
+ }
1512
+ // Fallthrough
1513
+ }
1514
+ case PENDING: {
1515
+ // If we're not yet initialized we need to skip what we've already drilled
1516
+ // through and then wait for the next value to become available.
1517
+ path.splice(0, i - 1);
1518
+ // Add "listener" to our new chunk dependency.
1519
+ if (referencedChunk.value === null) {
1520
+ referencedChunk.value = [reference];
1521
+ } else {
1522
+ referencedChunk.value.push(reference);
1523
+ }
1524
+ if (referencedChunk.reason === null) {
1525
+ referencedChunk.reason = [reference];
1526
+ } else {
1527
+ referencedChunk.reason.push(reference);
1528
+ }
1529
+ return;
1530
+ }
1531
+ case HALTED: {
1532
+ // Do nothing. We couldn't fulfill.
1533
+ // TODO: Mark downstreams as halted too.
1534
+ return;
1535
+ }
1536
+ default: {
1537
+ rejectReference(
1538
+ response,
1539
+ reference.handler,
1540
+ referencedChunk.reason,
1541
+ );
1542
+ return;
1543
+ }
1544
+ }
1545
+ }
1546
+ }
1547
+ value = value[path[i]];
1548
+ }
1549
+
1550
while (
1551
typeof value === 'object' &&
1552
value !== null &&
1553
value.$$typeof === REACT_LAZY_TYPE
1554
) {
1471
- // We never expect to see a Lazy node on this path because we encode those as
1472
- // separate models. This must mean that we have inserted an extra lazy node
1473
- // e.g. to replace a blocked element. We must instead look for it inside.
1555
+ // If what we're referencing is a Lazy it must be because we inserted one as a virtual node
1556
+ // while it was blocked by other data. If it's no longer blocked, we can unwrap it.
1557
const referencedChunk: SomeChunk<any> = value._payload;
1558
if (referencedChunk === handler.chunk) {
1559
// This is a reference to the thing we're currently blocking. We can peak
1574
value = referencedChunk.value;
1575
continue;
1576
}
1494
- case BLOCKED: {
1495
- // It is possible that we're blocked on our own chunk if it's a cycle.
1496
- // Before adding the listener to the inner chunk, let's check if it would
1497
- // result in a cycle.
1498
- const cyclicHandler = resolveBlockedCycle(
1499
- referencedChunk,
1500
- reference,
1501
- );
1502
- if (cyclicHandler !== null) {
1503
- // This reference points back to this chunk. We can resolve the cycle by
1504
- // using the value from that handler.
1505
- value = cyclicHandler.value;
1506
- continue;
1507
- }
1508
- // Fallthrough
1509
- }
1510
- case PENDING: {
1511
- // If we're not yet initialized we need to skip what we've already drilled
1512
- // through and then wait for the next value to become available.
1513
- path.splice(0, i - 1);
1514
- // Add "listener" to our new chunk dependency.
1515
- if (referencedChunk.value === null) {
1516
- referencedChunk.value = [reference];
1517
- } else {
1518
- referencedChunk.value.push(reference);
1519
- }
1520
- if (referencedChunk.reason === null) {
1521
- referencedChunk.reason = [reference];
1522
- } else {
1523
- referencedChunk.reason.push(reference);
1524
- }
1525
- return;
1526
- }
1527
- case HALTED: {
1528
- // Do nothing. We couldn't fulfill.
1529
- // TODO: Mark downstreams as halted too.
1530
- return;
1531
- }
1532
- default: {
1533
- rejectReference(
1534
- response,
1535
- reference.handler,
1536
- referencedChunk.reason,
1537
- );
1538
- return;
1539
- }
1577
}
1578
}
1579
+ break;
1580
}
1543
- value = value[path[i]];
1544
- }
1581
1546
- while (
1547
- typeof value === 'object' &&
1548
- value !== null &&
1549
- value.$$typeof === REACT_LAZY_TYPE
1550
- ) {
1551
- // If what we're referencing is a Lazy it must be because we inserted one as a virtual node
1552
- // while it was blocked by other data. If it's no longer blocked, we can unwrap it.
1553
- const referencedChunk: SomeChunk<any> = value._payload;
1554
- if (referencedChunk === handler.chunk) {
1555
- // This is a reference to the thing we're currently blocking. We can peak
1556
- // inside of it to get the value.
1557
- value = handler.value;
1558
- continue;
1559
- } else {
1560
- switch (referencedChunk.status) {
1561
- case RESOLVED_MODEL:
1562
- initializeModelChunk(referencedChunk);
1582
+ const mappedValue = map(response, value, parentObject, key);
1583
+ parentObject[key] = mappedValue;
1584
+
1585
+ // If this is the root object for a model reference, where `handler.value`
1586
+ // is a stale `null`, the resolved value can be used directly.
1587
+ if (key === '' && handler.value === null) {
1588
+ handler.value = mappedValue;
1589
+ }
1590
+
1591
+ // If the parent object is an unparsed React element tuple, we also need to
1592
+ // update the props and owner of the parsed element object (i.e.
1593
+ // handler.value).
1594
+ if (
1595
+ parentObject[0] === REACT_ELEMENT_TYPE &&
1596
+ typeof handler.value === 'object' &&
1597
+ handler.value !== null &&
1598
+ handler.value.$$typeof === REACT_ELEMENT_TYPE
1599
+ ) {
1600
+ const element: any = handler.value;
1601
+ switch (key) {
1602
+ case '3':
1603
+ transferReferencedDebugInfo(handler.chunk, fulfilledChunk);
1604
+ element.props = mappedValue;
1605
+ break;
1606
+ case '4':
1607
+ // This path doesn't call transferReferencedDebugInfo because this reference is to a debug chunk.
1608
+ if (__DEV__) {
1609
+ element._owner = mappedValue;
1610
+ }
1611
break;
1564
- case RESOLVED_MODULE:
1565
- initializeModuleChunk(referencedChunk);
1612
+ case '5':
1613
+ // This path doesn't call transferReferencedDebugInfo because this reference is to a debug chunk.
1614
+ if (__DEV__) {
1615
+ element._debugStack = mappedValue;
1616
+ }
1617
+ break;
1618
+ default:
1619
+ transferReferencedDebugInfo(handler.chunk, fulfilledChunk);
1620
break;
1621
}
1568
- switch (referencedChunk.status) {
1569
- case INITIALIZED: {
1570
- value = referencedChunk.value;
1571
- continue;
1572
- }
1573
- }
1574
- }
1575
- break;
1576
- }
1577
-
1578
- const mappedValue = map(response, value, parentObject, key);
1579
- parentObject[key] = mappedValue;
1580
-
1581
- // If this is the root object for a model reference, where `handler.value`
1582
- // is a stale `null`, the resolved value can be used directly.
1583
- if (key === '' && handler.value === null) {
1584
- handler.value = mappedValue;
1585
- }
1586
-
1587
- // If the parent object is an unparsed React element tuple, we also need to
1588
- // update the props and owner of the parsed element object (i.e.
1589
- // handler.value).
1590
- if (
1591
- parentObject[0] === REACT_ELEMENT_TYPE &&
1592
- typeof handler.value === 'object' &&
1593
- handler.value !== null &&
1594
- handler.value.$$typeof === REACT_ELEMENT_TYPE
1595
- ) {
1596
- const element: any = handler.value;
1597
- switch (key) {
1598
- case '3':
1599
- transferReferencedDebugInfo(handler.chunk, fulfilledChunk);
1600
- element.props = mappedValue;
1601
- break;
1602
- case '4':
1603
- // This path doesn't call transferReferencedDebugInfo because this reference is to a debug chunk.
1604
- if (__DEV__) {
1605
- element._owner = mappedValue;
1606
- }
1607
- break;
1608
- case '5':
1609
- // This path doesn't call transferReferencedDebugInfo because this reference is to a debug chunk.
1610
- if (__DEV__) {
1611
- element._debugStack = mappedValue;
1612
- }
1613
- break;
1614
- default:
1615
- transferReferencedDebugInfo(handler.chunk, fulfilledChunk);
1616
- break;
1622
+ } else if (__DEV__ && !reference.isDebug) {
1623
+ transferReferencedDebugInfo(handler.chunk, fulfilledChunk);
1624
}
1618
- } else if (__DEV__ && !reference.isDebug) {
1619
- transferReferencedDebugInfo(handler.chunk, fulfilledChunk);
1625
+ } catch (error) {
1626
+ rejectReference(response, reference.handler, error);
1627
+ return;
1628
}
1629
1630
handler.deps--;
1890
const initializedChunk: InitializedChunk<T> = (chunk: any);
1891
initializedChunk.status = INITIALIZED;
1892
initializedChunk.value = handler.value;
1893
+ initializedChunk.reason = null;
1894
if (resolveListeners !== null) {
1895
wakeChunk(response, resolveListeners, handler.value, initializedChunk);
1896
} else {
2368
// Symbol
2369
return Symbol.for(value.slice(2));
2370
}
2362
- case 'F': {
2371
+ case 'h': {
2372
// Server Reference
2373
const ref = value.slice(2);
2374
return getOutlinedModel(
3147
streamState: StreamState,
3148
): void {
3149
let controller: ReadableStreamController = (null: any);
3150
+ let closed = false;
3151
const stream = new ReadableStream({
3152
type: type,
3153
start(c) {
3205
}
3206
},
3207
close(json: UninitializedModel): void {
3208
+ if (closed) {
3209
+ return;
3210
+ }
3211
+ closed = true;
3212
if (previousBlockedChunk === null) {
3213
controller.close();
3214
} else {
3219
}
3220
},
3221
error(error: mixed): void {
3222
+ if (closed) {
3223
+ return;
3224
+ }
3225
+ closed = true;
3226
if (previousBlockedChunk === null) {
3227
// $FlowFixMe[incompatible-call]
3228
controller.error(error);
3283
(chunk: any);
3284
initializedChunk.status = INITIALIZED;
3285
initializedChunk.value = {done: false, value: value};
3286
+ initializedChunk.reason = null;
3287
if (resolveListeners !== null) {
3288
wakeChunkIfInitialized(
3289
response,
3313
nextWriteIndex++;
3314
},
3315
close(value: UninitializedModel): void {
3316
+ if (closed) {
3317
+ return;
3318
+ }
3319
closed = true;
3320
if (nextWriteIndex === buffer.length) {
3321
buffer[nextWriteIndex] = createResolvedIteratorResultChunk(
3343
}
3344
},
3345
error(error: Error): void {
3346
+ if (closed) {
3347
+ return;
3348
+ }
3349
closed = true;
3350
if (nextWriteIndex === buffer.length) {
3351
buffer[nextWriteIndex] =