1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. import type {Thenable} from 'shared/ReactTypes';
    
  11. import type {LazyComponent} from 'react/src/ReactLazy';
    
  12. 
    
  13. import type {
    
  14.   ClientReference,
    
  15.   ClientReferenceMetadata,
    
  16.   SSRModuleMap,
    
  17.   StringDecoder,
    
  18.   ModuleLoading,
    
  19. } from './ReactFlightClientConfig';
    
  20. 
    
  21. import type {
    
  22.   HintCode,
    
  23.   HintModel,
    
  24. } from 'react-server/src/ReactFlightServerConfig';
    
  25. 
    
  26. import type {CallServerCallback} from './ReactFlightReplyClient';
    
  27. 
    
  28. import type {Postpone} from 'react/src/ReactPostpone';
    
  29. 
    
  30. import {enableBinaryFlight, enablePostpone} from 'shared/ReactFeatureFlags';
    
  31. 
    
  32. import {
    
  33.   resolveClientReference,
    
  34.   preloadModule,
    
  35.   requireModule,
    
  36.   dispatchHint,
    
  37.   readPartialStringChunk,
    
  38.   readFinalStringChunk,
    
  39.   createStringDecoder,
    
  40.   prepareDestinationForModule,
    
  41. } from './ReactFlightClientConfig';
    
  42. 
    
  43. import {registerServerReference} from './ReactFlightReplyClient';
    
  44. 
    
  45. import {
    
  46.   REACT_LAZY_TYPE,
    
  47.   REACT_ELEMENT_TYPE,
    
  48.   REACT_POSTPONE_TYPE,
    
  49. } from 'shared/ReactSymbols';
    
  50. 
    
  51. import {getOrCreateServerContext} from 'shared/ReactServerContextRegistry';
    
  52. 
    
  53. export type {CallServerCallback};
    
  54. 
    
  55. type UninitializedModel = string;
    
  56. 
    
  57. export type JSONValue =
    
  58.   | number
    
  59.   | null
    
  60.   | boolean
    
  61.   | string
    
  62.   | {+[key: string]: JSONValue}
    
  63.   | $ReadOnlyArray<JSONValue>;
    
  64. 
    
  65. const ROW_ID = 0;
    
  66. const ROW_TAG = 1;
    
  67. const ROW_LENGTH = 2;
    
  68. const ROW_CHUNK_BY_NEWLINE = 3;
    
  69. const ROW_CHUNK_BY_LENGTH = 4;
    
  70. 
    
  71. type RowParserState = 0 | 1 | 2 | 3 | 4;
    
  72. 
    
  73. const PENDING = 'pending';
    
  74. const BLOCKED = 'blocked';
    
  75. const CYCLIC = 'cyclic';
    
  76. const RESOLVED_MODEL = 'resolved_model';
    
  77. const RESOLVED_MODULE = 'resolved_module';
    
  78. const INITIALIZED = 'fulfilled';
    
  79. const ERRORED = 'rejected';
    
  80. 
    
  81. type PendingChunk<T> = {
    
  82.   status: 'pending',
    
  83.   value: null | Array<(T) => mixed>,
    
  84.   reason: null | Array<(mixed) => mixed>,
    
  85.   _response: Response,
    
  86.   then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
    
  87. };
    
  88. type BlockedChunk<T> = {
    
  89.   status: 'blocked',
    
  90.   value: null | Array<(T) => mixed>,
    
  91.   reason: null | Array<(mixed) => mixed>,
    
  92.   _response: Response,
    
  93.   then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
    
  94. };
    
  95. type CyclicChunk<T> = {
    
  96.   status: 'cyclic',
    
  97.   value: null | Array<(T) => mixed>,
    
  98.   reason: null | Array<(mixed) => mixed>,
    
  99.   _response: Response,
    
  100.   then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
    
  101. };
    
  102. type ResolvedModelChunk<T> = {
    
  103.   status: 'resolved_model',
    
  104.   value: UninitializedModel,
    
  105.   reason: null,
    
  106.   _response: Response,
    
  107.   then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
    
  108. };
    
  109. type ResolvedModuleChunk<T> = {
    
  110.   status: 'resolved_module',
    
  111.   value: ClientReference<T>,
    
  112.   reason: null,
    
  113.   _response: Response,
    
  114.   then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
    
  115. };
    
  116. type InitializedChunk<T> = {
    
  117.   status: 'fulfilled',
    
  118.   value: T,
    
  119.   reason: null,
    
  120.   _response: Response,
    
  121.   then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
    
  122. };
    
  123. type ErroredChunk<T> = {
    
  124.   status: 'rejected',
    
  125.   value: null,
    
  126.   reason: mixed,
    
  127.   _response: Response,
    
  128.   then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
    
  129. };
    
  130. type SomeChunk<T> =
    
  131.   | PendingChunk<T>
    
  132.   | BlockedChunk<T>
    
  133.   | CyclicChunk<T>
    
  134.   | ResolvedModelChunk<T>
    
  135.   | ResolvedModuleChunk<T>
    
  136.   | InitializedChunk<T>
    
  137.   | ErroredChunk<T>;
    
  138. 
    
  139. // $FlowFixMe[missing-this-annot]
    
  140. function Chunk(status: any, value: any, reason: any, response: Response) {
    
  141.   this.status = status;
    
  142.   this.value = value;
    
  143.   this.reason = reason;
    
  144.   this._response = response;
    
  145. }
    
  146. // We subclass Promise.prototype so that we get other methods like .catch
    
  147. Chunk.prototype = (Object.create(Promise.prototype): any);
    
  148. // TODO: This doesn't return a new Promise chain unlike the real .then
    
  149. Chunk.prototype.then = function <T>(
    
  150.   this: SomeChunk<T>,
    
  151.   resolve: (value: T) => mixed,
    
  152.   reject: (reason: mixed) => mixed,
    
  153. ) {
    
  154.   const chunk: SomeChunk<T> = this;
    
  155.   // If we have resolved content, we try to initialize it first which
    
  156.   // might put us back into one of the other states.
    
  157.   switch (chunk.status) {
    
  158.     case RESOLVED_MODEL:
    
  159.       initializeModelChunk(chunk);
    
  160.       break;
    
  161.     case RESOLVED_MODULE:
    
  162.       initializeModuleChunk(chunk);
    
  163.       break;
    
  164.   }
    
  165.   // The status might have changed after initialization.
    
  166.   switch (chunk.status) {
    
  167.     case INITIALIZED:
    
  168.       resolve(chunk.value);
    
  169.       break;
    
  170.     case PENDING:
    
  171.     case BLOCKED:
    
  172.     case CYCLIC:
    
  173.       if (resolve) {
    
  174.         if (chunk.value === null) {
    
  175.           chunk.value = ([]: Array<(T) => mixed>);
    
  176.         }
    
  177.         chunk.value.push(resolve);
    
  178.       }
    
  179.       if (reject) {
    
  180.         if (chunk.reason === null) {
    
  181.           chunk.reason = ([]: Array<(mixed) => mixed>);
    
  182.         }
    
  183.         chunk.reason.push(reject);
    
  184.       }
    
  185.       break;
    
  186.     default:
    
  187.       reject(chunk.reason);
    
  188.       break;
    
  189.   }
    
  190. };
    
  191. 
    
  192. export type Response = {
    
  193.   _bundlerConfig: SSRModuleMap,
    
  194.   _moduleLoading: ModuleLoading,
    
  195.   _callServer: CallServerCallback,
    
  196.   _nonce: ?string,
    
  197.   _chunks: Map<number, SomeChunk<any>>,
    
  198.   _fromJSON: (key: string, value: JSONValue) => any,
    
  199.   _stringDecoder: StringDecoder,
    
  200.   _rowState: RowParserState,
    
  201.   _rowID: number, // parts of a row ID parsed so far
    
  202.   _rowTag: number, // 0 indicates that we're currently parsing the row ID
    
  203.   _rowLength: number, // remaining bytes in the row. 0 indicates that we're looking for a newline.
    
  204.   _buffer: Array<Uint8Array>, // chunks received so far as part of this row
    
  205. };
    
  206. 
    
  207. function readChunk<T>(chunk: SomeChunk<T>): T {
    
  208.   // If we have resolved content, we try to initialize it first which
    
  209.   // might put us back into one of the other states.
    
  210.   switch (chunk.status) {
    
  211.     case RESOLVED_MODEL:
    
  212.       initializeModelChunk(chunk);
    
  213.       break;
    
  214.     case RESOLVED_MODULE:
    
  215.       initializeModuleChunk(chunk);
    
  216.       break;
    
  217.   }
    
  218.   // The status might have changed after initialization.
    
  219.   switch (chunk.status) {
    
  220.     case INITIALIZED:
    
  221.       return chunk.value;
    
  222.     case PENDING:
    
  223.     case BLOCKED:
    
  224.     case CYCLIC:
    
  225.       // eslint-disable-next-line no-throw-literal
    
  226.       throw ((chunk: any): Thenable<T>);
    
  227.     default:
    
  228.       throw chunk.reason;
    
  229.   }
    
  230. }
    
  231. 
    
  232. export function getRoot<T>(response: Response): Thenable<T> {
    
  233.   const chunk = getChunk(response, 0);
    
  234.   return (chunk: any);
    
  235. }
    
  236. 
    
  237. function createPendingChunk<T>(response: Response): PendingChunk<T> {
    
  238.   // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
    
  239.   return new Chunk(PENDING, null, null, response);
    
  240. }
    
  241. 
    
  242. function createBlockedChunk<T>(response: Response): BlockedChunk<T> {
    
  243.   // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
    
  244.   return new Chunk(BLOCKED, null, null, response);
    
  245. }
    
  246. 
    
  247. function createErrorChunk<T>(
    
  248.   response: Response,
    
  249.   error: Error | Postpone,
    
  250. ): ErroredChunk<T> {
    
  251.   // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
    
  252.   return new Chunk(ERRORED, null, error, response);
    
  253. }
    
  254. 
    
  255. function wakeChunk<T>(listeners: Array<(T) => mixed>, value: T): void {
    
  256.   for (let i = 0; i < listeners.length; i++) {
    
  257.     const listener = listeners[i];
    
  258.     listener(value);
    
  259.   }
    
  260. }
    
  261. 
    
  262. function wakeChunkIfInitialized<T>(
    
  263.   chunk: SomeChunk<T>,
    
  264.   resolveListeners: Array<(T) => mixed>,
    
  265.   rejectListeners: null | Array<(mixed) => mixed>,
    
  266. ): void {
    
  267.   switch (chunk.status) {
    
  268.     case INITIALIZED:
    
  269.       wakeChunk(resolveListeners, chunk.value);
    
  270.       break;
    
  271.     case PENDING:
    
  272.     case BLOCKED:
    
  273.     case CYCLIC:
    
  274.       chunk.value = resolveListeners;
    
  275.       chunk.reason = rejectListeners;
    
  276.       break;
    
  277.     case ERRORED:
    
  278.       if (rejectListeners) {
    
  279.         wakeChunk(rejectListeners, chunk.reason);
    
  280.       }
    
  281.       break;
    
  282.   }
    
  283. }
    
  284. 
    
  285. function triggerErrorOnChunk<T>(chunk: SomeChunk<T>, error: mixed): void {
    
  286.   if (chunk.status !== PENDING && chunk.status !== BLOCKED) {
    
  287.     // We already resolved. We didn't expect to see this.
    
  288.     return;
    
  289.   }
    
  290.   const listeners = chunk.reason;
    
  291.   const erroredChunk: ErroredChunk<T> = (chunk: any);
    
  292.   erroredChunk.status = ERRORED;
    
  293.   erroredChunk.reason = error;
    
  294.   if (listeners !== null) {
    
  295.     wakeChunk(listeners, error);
    
  296.   }
    
  297. }
    
  298. 
    
  299. function createResolvedModelChunk<T>(
    
  300.   response: Response,
    
  301.   value: UninitializedModel,
    
  302. ): ResolvedModelChunk<T> {
    
  303.   // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
    
  304.   return new Chunk(RESOLVED_MODEL, value, null, response);
    
  305. }
    
  306. 
    
  307. function createResolvedModuleChunk<T>(
    
  308.   response: Response,
    
  309.   value: ClientReference<T>,
    
  310. ): ResolvedModuleChunk<T> {
    
  311.   // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
    
  312.   return new Chunk(RESOLVED_MODULE, value, null, response);
    
  313. }
    
  314. 
    
  315. function createInitializedTextChunk(
    
  316.   response: Response,
    
  317.   value: string,
    
  318. ): InitializedChunk<string> {
    
  319.   // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
    
  320.   return new Chunk(INITIALIZED, value, null, response);
    
  321. }
    
  322. 
    
  323. function createInitializedBufferChunk(
    
  324.   response: Response,
    
  325.   value: $ArrayBufferView | ArrayBuffer,
    
  326. ): InitializedChunk<Uint8Array> {
    
  327.   // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
    
  328.   return new Chunk(INITIALIZED, value, null, response);
    
  329. }
    
  330. 
    
  331. function resolveModelChunk<T>(
    
  332.   chunk: SomeChunk<T>,
    
  333.   value: UninitializedModel,
    
  334. ): void {
    
  335.   if (chunk.status !== PENDING) {
    
  336.     // We already resolved. We didn't expect to see this.
    
  337.     return;
    
  338.   }
    
  339.   const resolveListeners = chunk.value;
    
  340.   const rejectListeners = chunk.reason;
    
  341.   const resolvedChunk: ResolvedModelChunk<T> = (chunk: any);
    
  342.   resolvedChunk.status = RESOLVED_MODEL;
    
  343.   resolvedChunk.value = value;
    
  344.   if (resolveListeners !== null) {
    
  345.     // This is unfortunate that we're reading this eagerly if
    
  346.     // we already have listeners attached since they might no
    
  347.     // longer be rendered or might not be the highest pri.
    
  348.     initializeModelChunk(resolvedChunk);
    
  349.     // The status might have changed after initialization.
    
  350.     wakeChunkIfInitialized(chunk, resolveListeners, rejectListeners);
    
  351.   }
    
  352. }
    
  353. 
    
  354. function resolveModuleChunk<T>(
    
  355.   chunk: SomeChunk<T>,
    
  356.   value: ClientReference<T>,
    
  357. ): void {
    
  358.   if (chunk.status !== PENDING && chunk.status !== BLOCKED) {
    
  359.     // We already resolved. We didn't expect to see this.
    
  360.     return;
    
  361.   }
    
  362.   const resolveListeners = chunk.value;
    
  363.   const rejectListeners = chunk.reason;
    
  364.   const resolvedChunk: ResolvedModuleChunk<T> = (chunk: any);
    
  365.   resolvedChunk.status = RESOLVED_MODULE;
    
  366.   resolvedChunk.value = value;
    
  367.   if (resolveListeners !== null) {
    
  368.     initializeModuleChunk(resolvedChunk);
    
  369.     wakeChunkIfInitialized(chunk, resolveListeners, rejectListeners);
    
  370.   }
    
  371. }
    
  372. 
    
  373. let initializingChunk: ResolvedModelChunk<any> = (null: any);
    
  374. let initializingChunkBlockedModel: null | {deps: number, value: any} = null;
    
  375. function initializeModelChunk<T>(chunk: ResolvedModelChunk<T>): void {
    
  376.   const prevChunk = initializingChunk;
    
  377.   const prevBlocked = initializingChunkBlockedModel;
    
  378.   initializingChunk = chunk;
    
  379.   initializingChunkBlockedModel = null;
    
  380. 
    
  381.   const resolvedModel = chunk.value;
    
  382. 
    
  383.   // We go to the CYCLIC state until we've fully resolved this.
    
  384.   // We do this before parsing in case we try to initialize the same chunk
    
  385.   // while parsing the model. Such as in a cyclic reference.
    
  386.   const cyclicChunk: CyclicChunk<T> = (chunk: any);
    
  387.   cyclicChunk.status = CYCLIC;
    
  388.   cyclicChunk.value = null;
    
  389.   cyclicChunk.reason = null;
    
  390. 
    
  391.   try {
    
  392.     const value: T = parseModel(chunk._response, resolvedModel);
    
  393.     if (
    
  394.       initializingChunkBlockedModel !== null &&
    
  395.       initializingChunkBlockedModel.deps > 0
    
  396.     ) {
    
  397.       initializingChunkBlockedModel.value = value;
    
  398.       // We discovered new dependencies on modules that are not yet resolved.
    
  399.       // We have to go the BLOCKED state until they're resolved.
    
  400.       const blockedChunk: BlockedChunk<T> = (chunk: any);
    
  401.       blockedChunk.status = BLOCKED;
    
  402.       blockedChunk.value = null;
    
  403.       blockedChunk.reason = null;
    
  404.     } else {
    
  405.       const resolveListeners = cyclicChunk.value;
    
  406.       const initializedChunk: InitializedChunk<T> = (chunk: any);
    
  407.       initializedChunk.status = INITIALIZED;
    
  408.       initializedChunk.value = value;
    
  409.       if (resolveListeners !== null) {
    
  410.         wakeChunk(resolveListeners, value);
    
  411.       }
    
  412.     }
    
  413.   } catch (error) {
    
  414.     const erroredChunk: ErroredChunk<T> = (chunk: any);
    
  415.     erroredChunk.status = ERRORED;
    
  416.     erroredChunk.reason = error;
    
  417.   } finally {
    
  418.     initializingChunk = prevChunk;
    
  419.     initializingChunkBlockedModel = prevBlocked;
    
  420.   }
    
  421. }
    
  422. 
    
  423. function initializeModuleChunk<T>(chunk: ResolvedModuleChunk<T>): void {
    
  424.   try {
    
  425.     const value: T = requireModule(chunk.value);
    
  426.     const initializedChunk: InitializedChunk<T> = (chunk: any);
    
  427.     initializedChunk.status = INITIALIZED;
    
  428.     initializedChunk.value = value;
    
  429.   } catch (error) {
    
  430.     const erroredChunk: ErroredChunk<T> = (chunk: any);
    
  431.     erroredChunk.status = ERRORED;
    
  432.     erroredChunk.reason = error;
    
  433.   }
    
  434. }
    
  435. 
    
  436. // Report that any missing chunks in the model is now going to throw this
    
  437. // error upon read. Also notify any pending promises.
    
  438. export function reportGlobalError(response: Response, error: Error): void {
    
  439.   response._chunks.forEach(chunk => {
    
  440.     // If this chunk was already resolved or errored, it won't
    
  441.     // trigger an error but if it wasn't then we need to
    
  442.     // because we won't be getting any new data to resolve it.
    
  443.     if (chunk.status === PENDING) {
    
  444.       triggerErrorOnChunk(chunk, error);
    
  445.     }
    
  446.   });
    
  447. }
    
  448. 
    
  449. function createElement(
    
  450.   type: mixed,
    
  451.   key: mixed,
    
  452.   props: mixed,
    
  453. ): React$Element<any> {
    
  454.   const element: any = {
    
  455.     // This tag allows us to uniquely identify this as a React Element
    
  456.     $$typeof: REACT_ELEMENT_TYPE,
    
  457. 
    
  458.     // Built-in properties that belong on the element
    
  459.     type: type,
    
  460.     key: key,
    
  461.     ref: null,
    
  462.     props: props,
    
  463. 
    
  464.     // Record the component responsible for creating this element.
    
  465.     _owner: null,
    
  466.   };
    
  467.   if (__DEV__) {
    
  468.     // We don't really need to add any of these but keeping them for good measure.
    
  469.     // Unfortunately, _store is enumerable in jest matchers so for equality to
    
  470.     // work, I need to keep it or make _store non-enumerable in the other file.
    
  471.     element._store = ({}: {
    
  472.       validated?: boolean,
    
  473.     });
    
  474.     Object.defineProperty(element._store, 'validated', {
    
  475.       configurable: false,
    
  476.       enumerable: false,
    
  477.       writable: true,
    
  478.       value: true, // This element has already been validated on the server.
    
  479.     });
    
  480.     Object.defineProperty(element, '_self', {
    
  481.       configurable: false,
    
  482.       enumerable: false,
    
  483.       writable: false,
    
  484.       value: null,
    
  485.     });
    
  486.     Object.defineProperty(element, '_source', {
    
  487.       configurable: false,
    
  488.       enumerable: false,
    
  489.       writable: false,
    
  490.       value: null,
    
  491.     });
    
  492.   }
    
  493.   return element;
    
  494. }
    
  495. 
    
  496. function createLazyChunkWrapper<T>(
    
  497.   chunk: SomeChunk<T>,
    
  498. ): LazyComponent<T, SomeChunk<T>> {
    
  499.   const lazyType: LazyComponent<T, SomeChunk<T>> = {
    
  500.     $$typeof: REACT_LAZY_TYPE,
    
  501.     _payload: chunk,
    
  502.     _init: readChunk,
    
  503.   };
    
  504.   return lazyType;
    
  505. }
    
  506. 
    
  507. function getChunk(response: Response, id: number): SomeChunk<any> {
    
  508.   const chunks = response._chunks;
    
  509.   let chunk = chunks.get(id);
    
  510.   if (!chunk) {
    
  511.     chunk = createPendingChunk(response);
    
  512.     chunks.set(id, chunk);
    
  513.   }
    
  514.   return chunk;
    
  515. }
    
  516. 
    
  517. function createModelResolver<T>(
    
  518.   chunk: SomeChunk<T>,
    
  519.   parentObject: Object,
    
  520.   key: string,
    
  521.   cyclic: boolean,
    
  522. ): (value: any) => void {
    
  523.   let blocked;
    
  524.   if (initializingChunkBlockedModel) {
    
  525.     blocked = initializingChunkBlockedModel;
    
  526.     if (!cyclic) {
    
  527.       blocked.deps++;
    
  528.     }
    
  529.   } else {
    
  530.     blocked = initializingChunkBlockedModel = {
    
  531.       deps: cyclic ? 0 : 1,
    
  532.       value: (null: any),
    
  533.     };
    
  534.   }
    
  535.   return value => {
    
  536.     parentObject[key] = value;
    
  537.     blocked.deps--;
    
  538.     if (blocked.deps === 0) {
    
  539.       if (chunk.status !== BLOCKED) {
    
  540.         return;
    
  541.       }
    
  542.       const resolveListeners = chunk.value;
    
  543.       const initializedChunk: InitializedChunk<T> = (chunk: any);
    
  544.       initializedChunk.status = INITIALIZED;
    
  545.       initializedChunk.value = blocked.value;
    
  546.       if (resolveListeners !== null) {
    
  547.         wakeChunk(resolveListeners, blocked.value);
    
  548.       }
    
  549.     }
    
  550.   };
    
  551. }
    
  552. 
    
  553. function createModelReject<T>(chunk: SomeChunk<T>): (error: mixed) => void {
    
  554.   return (error: mixed) => triggerErrorOnChunk(chunk, error);
    
  555. }
    
  556. 
    
  557. function createServerReferenceProxy<A: Iterable<any>, T>(
    
  558.   response: Response,
    
  559.   metaData: {id: any, bound: null | Thenable<Array<any>>},
    
  560. ): (...A) => Promise<T> {
    
  561.   const callServer = response._callServer;
    
  562.   const proxy = function (): Promise<T> {
    
  563.     // $FlowFixMe[method-unbinding]
    
  564.     const args = Array.prototype.slice.call(arguments);
    
  565.     const p = metaData.bound;
    
  566.     if (!p) {
    
  567.       return callServer(metaData.id, args);
    
  568.     }
    
  569.     if (p.status === INITIALIZED) {
    
  570.       const bound = p.value;
    
  571.       return callServer(metaData.id, bound.concat(args));
    
  572.     }
    
  573.     // Since this is a fake Promise whose .then doesn't chain, we have to wrap it.
    
  574.     // TODO: Remove the wrapper once that's fixed.
    
  575.     return ((Promise.resolve(p): any): Promise<Array<any>>).then(
    
  576.       function (bound) {
    
  577.         return callServer(metaData.id, bound.concat(args));
    
  578.       },
    
  579.     );
    
  580.   };
    
  581.   registerServerReference(proxy, metaData);
    
  582.   return proxy;
    
  583. }
    
  584. 
    
  585. function getOutlinedModel(response: Response, id: number): any {
    
  586.   const chunk = getChunk(response, id);
    
  587.   switch (chunk.status) {
    
  588.     case RESOLVED_MODEL:
    
  589.       initializeModelChunk(chunk);
    
  590.       break;
    
  591.   }
    
  592.   // The status might have changed after initialization.
    
  593.   switch (chunk.status) {
    
  594.     case INITIALIZED: {
    
  595.       return chunk.value;
    
  596.     }
    
  597.     // We always encode it first in the stream so it won't be pending.
    
  598.     default:
    
  599.       throw chunk.reason;
    
  600.   }
    
  601. }
    
  602. 
    
  603. function parseModelString(
    
  604.   response: Response,
    
  605.   parentObject: Object,
    
  606.   key: string,
    
  607.   value: string,
    
  608. ): any {
    
  609.   if (value[0] === '$') {
    
  610.     if (value === '$') {
    
  611.       // A very common symbol.
    
  612.       return REACT_ELEMENT_TYPE;
    
  613.     }
    
  614.     switch (value[1]) {
    
  615.       case '$': {
    
  616.         // This was an escaped string value.
    
  617.         return value.slice(1);
    
  618.       }
    
  619.       case 'L': {
    
  620.         // Lazy node
    
  621.         const id = parseInt(value.slice(2), 16);
    
  622.         const chunk = getChunk(response, id);
    
  623.         // We create a React.lazy wrapper around any lazy values.
    
  624.         // When passed into React, we'll know how to suspend on this.
    
  625.         return createLazyChunkWrapper(chunk);
    
  626.       }
    
  627.       case '@': {
    
  628.         // Promise
    
  629.         const id = parseInt(value.slice(2), 16);
    
  630.         const chunk = getChunk(response, id);
    
  631.         return chunk;
    
  632.       }
    
  633.       case 'S': {
    
  634.         // Symbol
    
  635.         return Symbol.for(value.slice(2));
    
  636.       }
    
  637.       case 'P': {
    
  638.         // Server Context Provider
    
  639.         return getOrCreateServerContext(value.slice(2)).Provider;
    
  640.       }
    
  641.       case 'F': {
    
  642.         // Server Reference
    
  643.         const id = parseInt(value.slice(2), 16);
    
  644.         const metadata = getOutlinedModel(response, id);
    
  645.         return createServerReferenceProxy(response, metadata);
    
  646.       }
    
  647.       case 'Q': {
    
  648.         // Map
    
  649.         const id = parseInt(value.slice(2), 16);
    
  650.         const data = getOutlinedModel(response, id);
    
  651.         return new Map(data);
    
  652.       }
    
  653.       case 'W': {
    
  654.         // Set
    
  655.         const id = parseInt(value.slice(2), 16);
    
  656.         const data = getOutlinedModel(response, id);
    
  657.         return new Set(data);
    
  658.       }
    
  659.       case 'I': {
    
  660.         // $Infinity
    
  661.         return Infinity;
    
  662.       }
    
  663.       case '-': {
    
  664.         // $-0 or $-Infinity
    
  665.         if (value === '$-0') {
    
  666.           return -0;
    
  667.         } else {
    
  668.           return -Infinity;
    
  669.         }
    
  670.       }
    
  671.       case 'N': {
    
  672.         // $NaN
    
  673.         return NaN;
    
  674.       }
    
  675.       case 'u': {
    
  676.         // matches "$undefined"
    
  677.         // Special encoding for `undefined` which can't be serialized as JSON otherwise.
    
  678.         return undefined;
    
  679.       }
    
  680.       case 'D': {
    
  681.         // Date
    
  682.         return new Date(Date.parse(value.slice(2)));
    
  683.       }
    
  684.       case 'n': {
    
  685.         // BigInt
    
  686.         return BigInt(value.slice(2));
    
  687.       }
    
  688.       default: {
    
  689.         // We assume that anything else is a reference ID.
    
  690.         const id = parseInt(value.slice(1), 16);
    
  691.         const chunk = getChunk(response, id);
    
  692.         switch (chunk.status) {
    
  693.           case RESOLVED_MODEL:
    
  694.             initializeModelChunk(chunk);
    
  695.             break;
    
  696.           case RESOLVED_MODULE:
    
  697.             initializeModuleChunk(chunk);
    
  698.             break;
    
  699.         }
    
  700.         // The status might have changed after initialization.
    
  701.         switch (chunk.status) {
    
  702.           case INITIALIZED:
    
  703.             return chunk.value;
    
  704.           case PENDING:
    
  705.           case BLOCKED:
    
  706.           case CYCLIC:
    
  707.             const parentChunk = initializingChunk;
    
  708.             chunk.then(
    
  709.               createModelResolver(
    
  710.                 parentChunk,
    
  711.                 parentObject,
    
  712.                 key,
    
  713.                 chunk.status === CYCLIC,
    
  714.               ),
    
  715.               createModelReject(parentChunk),
    
  716.             );
    
  717.             return null;
    
  718.           default:
    
  719.             throw chunk.reason;
    
  720.         }
    
  721.       }
    
  722.     }
    
  723.   }
    
  724.   return value;
    
  725. }
    
  726. 
    
  727. function parseModelTuple(
    
  728.   response: Response,
    
  729.   value: {+[key: string]: JSONValue} | $ReadOnlyArray<JSONValue>,
    
  730. ): any {
    
  731.   const tuple: [mixed, mixed, mixed, mixed] = (value: any);
    
  732. 
    
  733.   if (tuple[0] === REACT_ELEMENT_TYPE) {
    
  734.     // TODO: Consider having React just directly accept these arrays as elements.
    
  735.     // Or even change the ReactElement type to be an array.
    
  736.     return createElement(tuple[1], tuple[2], tuple[3]);
    
  737.   }
    
  738.   return value;
    
  739. }
    
  740. 
    
  741. function missingCall() {
    
  742.   throw new Error(
    
  743.     'Trying to call a function from "use server" but the callServer option ' +
    
  744.       'was not implemented in your router runtime.',
    
  745.   );
    
  746. }
    
  747. 
    
  748. export function createResponse(
    
  749.   bundlerConfig: SSRModuleMap,
    
  750.   moduleLoading: ModuleLoading,
    
  751.   callServer: void | CallServerCallback,
    
  752.   nonce: void | string,
    
  753. ): Response {
    
  754.   const chunks: Map<number, SomeChunk<any>> = new Map();
    
  755.   const response: Response = {
    
  756.     _bundlerConfig: bundlerConfig,
    
  757.     _moduleLoading: moduleLoading,
    
  758.     _callServer: callServer !== undefined ? callServer : missingCall,
    
  759.     _nonce: nonce,
    
  760.     _chunks: chunks,
    
  761.     _stringDecoder: createStringDecoder(),
    
  762.     _fromJSON: (null: any),
    
  763.     _rowState: 0,
    
  764.     _rowID: 0,
    
  765.     _rowTag: 0,
    
  766.     _rowLength: 0,
    
  767.     _buffer: [],
    
  768.   };
    
  769.   // Don't inline this call because it causes closure to outline the call above.
    
  770.   response._fromJSON = createFromJSONCallback(response);
    
  771.   return response;
    
  772. }
    
  773. 
    
  774. function resolveModel(
    
  775.   response: Response,
    
  776.   id: number,
    
  777.   model: UninitializedModel,
    
  778. ): void {
    
  779.   const chunks = response._chunks;
    
  780.   const chunk = chunks.get(id);
    
  781.   if (!chunk) {
    
  782.     chunks.set(id, createResolvedModelChunk(response, model));
    
  783.   } else {
    
  784.     resolveModelChunk(chunk, model);
    
  785.   }
    
  786. }
    
  787. 
    
  788. function resolveText(response: Response, id: number, text: string): void {
    
  789.   const chunks = response._chunks;
    
  790.   // We assume that we always reference large strings after they've been
    
  791.   // emitted.
    
  792.   chunks.set(id, createInitializedTextChunk(response, text));
    
  793. }
    
  794. 
    
  795. function resolveBuffer(
    
  796.   response: Response,
    
  797.   id: number,
    
  798.   buffer: $ArrayBufferView | ArrayBuffer,
    
  799. ): void {
    
  800.   const chunks = response._chunks;
    
  801.   // We assume that we always reference buffers after they've been emitted.
    
  802.   chunks.set(id, createInitializedBufferChunk(response, buffer));
    
  803. }
    
  804. 
    
  805. function resolveModule(
    
  806.   response: Response,
    
  807.   id: number,
    
  808.   model: UninitializedModel,
    
  809. ): void {
    
  810.   const chunks = response._chunks;
    
  811.   const chunk = chunks.get(id);
    
  812.   const clientReferenceMetadata: ClientReferenceMetadata = parseModel(
    
  813.     response,
    
  814.     model,
    
  815.   );
    
  816.   const clientReference = resolveClientReference<$FlowFixMe>(
    
  817.     response._bundlerConfig,
    
  818.     clientReferenceMetadata,
    
  819.   );
    
  820. 
    
  821.   prepareDestinationForModule(
    
  822.     response._moduleLoading,
    
  823.     response._nonce,
    
  824.     clientReferenceMetadata,
    
  825.   );
    
  826. 
    
  827.   // TODO: Add an option to encode modules that are lazy loaded.
    
  828.   // For now we preload all modules as early as possible since it's likely
    
  829.   // that we'll need them.
    
  830.   const promise = preloadModule(clientReference);
    
  831.   if (promise) {
    
  832.     let blockedChunk: BlockedChunk<any>;
    
  833.     if (!chunk) {
    
  834.       // Technically, we should just treat promise as the chunk in this
    
  835.       // case. Because it'll just behave as any other promise.
    
  836.       blockedChunk = createBlockedChunk(response);
    
  837.       chunks.set(id, blockedChunk);
    
  838.     } else {
    
  839.       // This can't actually happen because we don't have any forward
    
  840.       // references to modules.
    
  841.       blockedChunk = (chunk: any);
    
  842.       blockedChunk.status = BLOCKED;
    
  843.     }
    
  844.     promise.then(
    
  845.       () => resolveModuleChunk(blockedChunk, clientReference),
    
  846.       error => triggerErrorOnChunk(blockedChunk, error),
    
  847.     );
    
  848.   } else {
    
  849.     if (!chunk) {
    
  850.       chunks.set(id, createResolvedModuleChunk(response, clientReference));
    
  851.     } else {
    
  852.       // This can't actually happen because we don't have any forward
    
  853.       // references to modules.
    
  854.       resolveModuleChunk(chunk, clientReference);
    
  855.     }
    
  856.   }
    
  857. }
    
  858. 
    
  859. type ErrorWithDigest = Error & {digest?: string};
    
  860. function resolveErrorProd(
    
  861.   response: Response,
    
  862.   id: number,
    
  863.   digest: string,
    
  864. ): void {
    
  865.   if (__DEV__) {
    
  866.     // These errors should never make it into a build so we don't need to encode them in codes.json
    
  867.     // eslint-disable-next-line react-internal/prod-error-codes
    
  868.     throw new Error(
    
  869.       'resolveErrorProd should never be called in development mode. Use resolveErrorDev instead. This is a bug in React.',
    
  870.     );
    
  871.   }
    
  872.   const error = new Error(
    
  873.     'An error occurred in the Server Components render. The specific message is omitted in production' +
    
  874.       ' builds to avoid leaking sensitive details. A digest property is included on this error instance which' +
    
  875.       ' may provide additional details about the nature of the error.',
    
  876.   );
    
  877.   error.stack = 'Error: ' + error.message;
    
  878.   (error: any).digest = digest;
    
  879.   const errorWithDigest: ErrorWithDigest = (error: any);
    
  880.   const chunks = response._chunks;
    
  881.   const chunk = chunks.get(id);
    
  882.   if (!chunk) {
    
  883.     chunks.set(id, createErrorChunk(response, errorWithDigest));
    
  884.   } else {
    
  885.     triggerErrorOnChunk(chunk, errorWithDigest);
    
  886.   }
    
  887. }
    
  888. 
    
  889. function resolveErrorDev(
    
  890.   response: Response,
    
  891.   id: number,
    
  892.   digest: string,
    
  893.   message: string,
    
  894.   stack: string,
    
  895. ): void {
    
  896.   if (!__DEV__) {
    
  897.     // These errors should never make it into a build so we don't need to encode them in codes.json
    
  898.     // eslint-disable-next-line react-internal/prod-error-codes
    
  899.     throw new Error(
    
  900.       'resolveErrorDev should never be called in production mode. Use resolveErrorProd instead. This is a bug in React.',
    
  901.     );
    
  902.   }
    
  903.   // eslint-disable-next-line react-internal/prod-error-codes
    
  904.   const error = new Error(
    
  905.     message ||
    
  906.       'An error occurred in the Server Components render but no message was provided',
    
  907.   );
    
  908.   error.stack = stack;
    
  909.   (error: any).digest = digest;
    
  910.   const errorWithDigest: ErrorWithDigest = (error: any);
    
  911.   const chunks = response._chunks;
    
  912.   const chunk = chunks.get(id);
    
  913.   if (!chunk) {
    
  914.     chunks.set(id, createErrorChunk(response, errorWithDigest));
    
  915.   } else {
    
  916.     triggerErrorOnChunk(chunk, errorWithDigest);
    
  917.   }
    
  918. }
    
  919. 
    
  920. function resolvePostponeProd(response: Response, id: number): void {
    
  921.   if (__DEV__) {
    
  922.     // These errors should never make it into a build so we don't need to encode them in codes.json
    
  923.     // eslint-disable-next-line react-internal/prod-error-codes
    
  924.     throw new Error(
    
  925.       'resolvePostponeProd should never be called in development mode. Use resolvePostponeDev instead. This is a bug in React.',
    
  926.     );
    
  927.   }
    
  928.   const error = new Error(
    
  929.     'A Server Component was postponed. The reason is omitted in production' +
    
  930.       ' builds to avoid leaking sensitive details.',
    
  931.   );
    
  932.   const postponeInstance: Postpone = (error: any);
    
  933.   postponeInstance.$$typeof = REACT_POSTPONE_TYPE;
    
  934.   postponeInstance.stack = 'Error: ' + error.message;
    
  935.   const chunks = response._chunks;
    
  936.   const chunk = chunks.get(id);
    
  937.   if (!chunk) {
    
  938.     chunks.set(id, createErrorChunk(response, postponeInstance));
    
  939.   } else {
    
  940.     triggerErrorOnChunk(chunk, postponeInstance);
    
  941.   }
    
  942. }
    
  943. 
    
  944. function resolvePostponeDev(
    
  945.   response: Response,
    
  946.   id: number,
    
  947.   reason: string,
    
  948.   stack: string,
    
  949. ): void {
    
  950.   if (!__DEV__) {
    
  951.     // These errors should never make it into a build so we don't need to encode them in codes.json
    
  952.     // eslint-disable-next-line react-internal/prod-error-codes
    
  953.     throw new Error(
    
  954.       'resolvePostponeDev should never be called in production mode. Use resolvePostponeProd instead. This is a bug in React.',
    
  955.     );
    
  956.   }
    
  957.   // eslint-disable-next-line react-internal/prod-error-codes
    
  958.   const error = new Error(reason || '');
    
  959.   const postponeInstance: Postpone = (error: any);
    
  960.   postponeInstance.$$typeof = REACT_POSTPONE_TYPE;
    
  961.   postponeInstance.stack = stack;
    
  962.   const chunks = response._chunks;
    
  963.   const chunk = chunks.get(id);
    
  964.   if (!chunk) {
    
  965.     chunks.set(id, createErrorChunk(response, postponeInstance));
    
  966.   } else {
    
  967.     triggerErrorOnChunk(chunk, postponeInstance);
    
  968.   }
    
  969. }
    
  970. 
    
  971. function resolveHint<Code: HintCode>(
    
  972.   response: Response,
    
  973.   code: Code,
    
  974.   model: UninitializedModel,
    
  975. ): void {
    
  976.   const hintModel: HintModel<Code> = parseModel(response, model);
    
  977.   dispatchHint(code, hintModel);
    
  978. }
    
  979. 
    
  980. function mergeBuffer(
    
  981.   buffer: Array<Uint8Array>,
    
  982.   lastChunk: Uint8Array,
    
  983. ): Uint8Array {
    
  984.   const l = buffer.length;
    
  985.   // Count the bytes we'll need
    
  986.   let byteLength = lastChunk.length;
    
  987.   for (let i = 0; i < l; i++) {
    
  988.     byteLength += buffer[i].byteLength;
    
  989.   }
    
  990.   // Allocate enough contiguous space
    
  991.   const result = new Uint8Array(byteLength);
    
  992.   let offset = 0;
    
  993.   // Copy all the buffers into it.
    
  994.   for (let i = 0; i < l; i++) {
    
  995.     const chunk = buffer[i];
    
  996.     result.set(chunk, offset);
    
  997.     offset += chunk.byteLength;
    
  998.   }
    
  999.   result.set(lastChunk, offset);
    
  1000.   return result;
    
  1001. }
    
  1002. 
    
  1003. function resolveTypedArray(
    
  1004.   response: Response,
    
  1005.   id: number,
    
  1006.   buffer: Array<Uint8Array>,
    
  1007.   lastChunk: Uint8Array,
    
  1008.   constructor: any,
    
  1009.   bytesPerElement: number,
    
  1010. ): void {
    
  1011.   // If the view fits into one original buffer, we just reuse that buffer instead of
    
  1012.   // copying it out to a separate copy. This means that it's not always possible to
    
  1013.   // transfer these values to other threads without copying first since they may
    
  1014.   // share array buffer. For this to work, it must also have bytes aligned to a
    
  1015.   // multiple of a size of the type.
    
  1016.   const chunk =
    
  1017.     buffer.length === 0 && lastChunk.byteOffset % bytesPerElement === 0
    
  1018.       ? lastChunk
    
  1019.       : mergeBuffer(buffer, lastChunk);
    
  1020.   // TODO: The transfer protocol of RSC is little-endian. If the client isn't little-endian
    
  1021.   // we should convert it instead. In practice big endian isn't really Web compatible so it's
    
  1022.   // somewhat safe to assume that browsers aren't going to run it, but maybe there's some SSR
    
  1023.   // server that's affected.
    
  1024.   const view: $ArrayBufferView = new constructor(
    
  1025.     chunk.buffer,
    
  1026.     chunk.byteOffset,
    
  1027.     chunk.byteLength / bytesPerElement,
    
  1028.   );
    
  1029.   resolveBuffer(response, id, view);
    
  1030. }
    
  1031. 
    
  1032. function processFullRow(
    
  1033.   response: Response,
    
  1034.   id: number,
    
  1035.   tag: number,
    
  1036.   buffer: Array<Uint8Array>,
    
  1037.   chunk: Uint8Array,
    
  1038. ): void {
    
  1039.   if (enableBinaryFlight) {
    
  1040.     switch (tag) {
    
  1041.       case 65 /* "A" */:
    
  1042.         // We must always clone to extract it into a separate buffer instead of just a view.
    
  1043.         resolveBuffer(response, id, mergeBuffer(buffer, chunk).buffer);
    
  1044.         return;
    
  1045.       case 67 /* "C" */:
    
  1046.         resolveTypedArray(response, id, buffer, chunk, Int8Array, 1);
    
  1047.         return;
    
  1048.       case 99 /* "c" */:
    
  1049.         resolveBuffer(
    
  1050.           response,
    
  1051.           id,
    
  1052.           buffer.length === 0 ? chunk : mergeBuffer(buffer, chunk),
    
  1053.         );
    
  1054.         return;
    
  1055.       case 85 /* "U" */:
    
  1056.         resolveTypedArray(response, id, buffer, chunk, Uint8ClampedArray, 1);
    
  1057.         return;
    
  1058.       case 83 /* "S" */:
    
  1059.         resolveTypedArray(response, id, buffer, chunk, Int16Array, 2);
    
  1060.         return;
    
  1061.       case 115 /* "s" */:
    
  1062.         resolveTypedArray(response, id, buffer, chunk, Uint16Array, 2);
    
  1063.         return;
    
  1064.       case 76 /* "L" */:
    
  1065.         resolveTypedArray(response, id, buffer, chunk, Int32Array, 4);
    
  1066.         return;
    
  1067.       case 108 /* "l" */:
    
  1068.         resolveTypedArray(response, id, buffer, chunk, Uint32Array, 4);
    
  1069.         return;
    
  1070.       case 70 /* "F" */:
    
  1071.         resolveTypedArray(response, id, buffer, chunk, Float32Array, 4);
    
  1072.         return;
    
  1073.       case 68 /* "D" */:
    
  1074.         resolveTypedArray(response, id, buffer, chunk, Float64Array, 8);
    
  1075.         return;
    
  1076.       case 78 /* "N" */:
    
  1077.         resolveTypedArray(response, id, buffer, chunk, BigInt64Array, 8);
    
  1078.         return;
    
  1079.       case 109 /* "m" */:
    
  1080.         resolveTypedArray(response, id, buffer, chunk, BigUint64Array, 8);
    
  1081.         return;
    
  1082.       case 86 /* "V" */:
    
  1083.         resolveTypedArray(response, id, buffer, chunk, DataView, 1);
    
  1084.         return;
    
  1085.     }
    
  1086.   }
    
  1087. 
    
  1088.   const stringDecoder = response._stringDecoder;
    
  1089.   let row = '';
    
  1090.   for (let i = 0; i < buffer.length; i++) {
    
  1091.     row += readPartialStringChunk(stringDecoder, buffer[i]);
    
  1092.   }
    
  1093.   row += readFinalStringChunk(stringDecoder, chunk);
    
  1094.   switch (tag) {
    
  1095.     case 73 /* "I" */: {
    
  1096.       resolveModule(response, id, row);
    
  1097.       return;
    
  1098.     }
    
  1099.     case 72 /* "H" */: {
    
  1100.       const code: HintCode = (row[0]: any);
    
  1101.       resolveHint(response, code, row.slice(1));
    
  1102.       return;
    
  1103.     }
    
  1104.     case 69 /* "E" */: {
    
  1105.       const errorInfo = JSON.parse(row);
    
  1106.       if (__DEV__) {
    
  1107.         resolveErrorDev(
    
  1108.           response,
    
  1109.           id,
    
  1110.           errorInfo.digest,
    
  1111.           errorInfo.message,
    
  1112.           errorInfo.stack,
    
  1113.         );
    
  1114.       } else {
    
  1115.         resolveErrorProd(response, id, errorInfo.digest);
    
  1116.       }
    
  1117.       return;
    
  1118.     }
    
  1119.     case 84 /* "T" */: {
    
  1120.       resolveText(response, id, row);
    
  1121.       return;
    
  1122.     }
    
  1123.     case 80 /* "P" */: {
    
  1124.       if (enablePostpone) {
    
  1125.         if (__DEV__) {
    
  1126.           const postponeInfo = JSON.parse(row);
    
  1127.           resolvePostponeDev(
    
  1128.             response,
    
  1129.             id,
    
  1130.             postponeInfo.reason,
    
  1131.             postponeInfo.stack,
    
  1132.           );
    
  1133.         } else {
    
  1134.           resolvePostponeProd(response, id);
    
  1135.         }
    
  1136.         return;
    
  1137.       }
    
  1138.     }
    
  1139.     // Fallthrough
    
  1140.     default: /* """ "{" "[" "t" "f" "n" "0" - "9" */ {
    
  1141.       // We assume anything else is JSON.
    
  1142.       resolveModel(response, id, row);
    
  1143.       return;
    
  1144.     }
    
  1145.   }
    
  1146. }
    
  1147. 
    
  1148. export function processBinaryChunk(
    
  1149.   response: Response,
    
  1150.   chunk: Uint8Array,
    
  1151. ): void {
    
  1152.   let i = 0;
    
  1153.   let rowState = response._rowState;
    
  1154.   let rowID = response._rowID;
    
  1155.   let rowTag = response._rowTag;
    
  1156.   let rowLength = response._rowLength;
    
  1157.   const buffer = response._buffer;
    
  1158.   const chunkLength = chunk.length;
    
  1159.   while (i < chunkLength) {
    
  1160.     let lastIdx = -1;
    
  1161.     switch (rowState) {
    
  1162.       case ROW_ID: {
    
  1163.         const byte = chunk[i++];
    
  1164.         if (byte === 58 /* ":" */) {
    
  1165.           // Finished the rowID, next we'll parse the tag.
    
  1166.           rowState = ROW_TAG;
    
  1167.         } else {
    
  1168.           rowID = (rowID << 4) | (byte > 96 ? byte - 87 : byte - 48);
    
  1169.         }
    
  1170.         continue;
    
  1171.       }
    
  1172.       case ROW_TAG: {
    
  1173.         const resolvedRowTag = chunk[i];
    
  1174.         if (
    
  1175.           resolvedRowTag === 84 /* "T" */ ||
    
  1176.           (enableBinaryFlight &&
    
  1177.             (resolvedRowTag === 65 /* "A" */ ||
    
  1178.               resolvedRowTag === 67 /* "C" */ ||
    
  1179.               resolvedRowTag === 99 /* "c" */ ||
    
  1180.               resolvedRowTag === 85 /* "U" */ ||
    
  1181.               resolvedRowTag === 83 /* "S" */ ||
    
  1182.               resolvedRowTag === 115 /* "s" */ ||
    
  1183.               resolvedRowTag === 76 /* "L" */ ||
    
  1184.               resolvedRowTag === 108 /* "l" */ ||
    
  1185.               resolvedRowTag === 70 /* "F" */ ||
    
  1186.               resolvedRowTag === 68 /* "D" */ ||
    
  1187.               resolvedRowTag === 78 /* "N" */ ||
    
  1188.               resolvedRowTag === 109 /* "m" */ ||
    
  1189.               resolvedRowTag === 86)) /* "V" */
    
  1190.         ) {
    
  1191.           rowTag = resolvedRowTag;
    
  1192.           rowState = ROW_LENGTH;
    
  1193.           i++;
    
  1194.         } else if (resolvedRowTag > 64 && resolvedRowTag < 91 /* "A"-"Z" */) {
    
  1195.           rowTag = resolvedRowTag;
    
  1196.           rowState = ROW_CHUNK_BY_NEWLINE;
    
  1197.           i++;
    
  1198.         } else {
    
  1199.           rowTag = 0;
    
  1200.           rowState = ROW_CHUNK_BY_NEWLINE;
    
  1201.           // This was an unknown tag so it was probably part of the data.
    
  1202.         }
    
  1203.         continue;
    
  1204.       }
    
  1205.       case ROW_LENGTH: {
    
  1206.         const byte = chunk[i++];
    
  1207.         if (byte === 44 /* "," */) {
    
  1208.           // Finished the rowLength, next we'll buffer up to that length.
    
  1209.           rowState = ROW_CHUNK_BY_LENGTH;
    
  1210.         } else {
    
  1211.           rowLength = (rowLength << 4) | (byte > 96 ? byte - 87 : byte - 48);
    
  1212.         }
    
  1213.         continue;
    
  1214.       }
    
  1215.       case ROW_CHUNK_BY_NEWLINE: {
    
  1216.         // We're looking for a newline
    
  1217.         lastIdx = chunk.indexOf(10 /* "\n" */, i);
    
  1218.         break;
    
  1219.       }
    
  1220.       case ROW_CHUNK_BY_LENGTH: {
    
  1221.         // We're looking for the remaining byte length
    
  1222.         lastIdx = i + rowLength;
    
  1223.         if (lastIdx > chunk.length) {
    
  1224.           lastIdx = -1;
    
  1225.         }
    
  1226.         break;
    
  1227.       }
    
  1228.     }
    
  1229.     const offset = chunk.byteOffset + i;
    
  1230.     if (lastIdx > -1) {
    
  1231.       // We found the last chunk of the row
    
  1232.       const length = lastIdx - i;
    
  1233.       const lastChunk = new Uint8Array(chunk.buffer, offset, length);
    
  1234.       processFullRow(response, rowID, rowTag, buffer, lastChunk);
    
  1235.       // Reset state machine for a new row
    
  1236.       i = lastIdx;
    
  1237.       if (rowState === ROW_CHUNK_BY_NEWLINE) {
    
  1238.         // If we're trailing by a newline we need to skip it.
    
  1239.         i++;
    
  1240.       }
    
  1241.       rowState = ROW_ID;
    
  1242.       rowTag = 0;
    
  1243.       rowID = 0;
    
  1244.       rowLength = 0;
    
  1245.       buffer.length = 0;
    
  1246.     } else {
    
  1247.       // The rest of this row is in a future chunk. We stash the rest of the
    
  1248.       // current chunk until we can process the full row.
    
  1249.       const length = chunk.byteLength - i;
    
  1250.       const remainingSlice = new Uint8Array(chunk.buffer, offset, length);
    
  1251.       buffer.push(remainingSlice);
    
  1252.       // Update how many bytes we're still waiting for. If we're looking for
    
  1253.       // a newline, this doesn't hurt since we'll just ignore it.
    
  1254.       rowLength -= remainingSlice.byteLength;
    
  1255.       break;
    
  1256.     }
    
  1257.   }
    
  1258.   response._rowState = rowState;
    
  1259.   response._rowID = rowID;
    
  1260.   response._rowTag = rowTag;
    
  1261.   response._rowLength = rowLength;
    
  1262. }
    
  1263. 
    
  1264. function parseModel<T>(response: Response, json: UninitializedModel): T {
    
  1265.   return JSON.parse(json, response._fromJSON);
    
  1266. }
    
  1267. 
    
  1268. function createFromJSONCallback(response: Response) {
    
  1269.   // $FlowFixMe[missing-this-annot]
    
  1270.   return function (key: string, value: JSONValue) {
    
  1271.     if (typeof value === 'string') {
    
  1272.       // We can't use .bind here because we need the "this" value.
    
  1273.       return parseModelString(response, this, key, value);
    
  1274.     }
    
  1275.     if (typeof value === 'object' && value !== null) {
    
  1276.       return parseModelTuple(response, value);
    
  1277.     }
    
  1278.     return value;
    
  1279.   };
    
  1280. }
    
  1281. 
    
  1282. export function close(response: Response): void {
    
  1283.   // In case there are any remaining unresolved chunks, they won't
    
  1284.   // be resolved now. So we need to issue an error to those.
    
  1285.   // Ideally we should be able to early bail out if we kept a
    
  1286.   // ref count of pending chunks.
    
  1287.   reportGlobalError(response, new Error('Connection closed.'));
    
  1288. }