');case 3:return a.push('
');case 4:return a.push('');case 5:return a.push('');case 6:return a.push('');case 7:return a.push('');case 8:return a.push('');default:throw Error("Unknown insertion mode. This is a bug in React.");}}
-function Xb(a,b){switch(b.insertionMode){case 0:case 1:case 2:return a.push("");case 3:return a.push("");case 4:return a.push("");case 5:return a.push("
");case 6:return a.push("
");case 7:return a.push("
");case 8:return a.push("
");default:throw Error("Unknown insertion mode. This is a bug in React.");}}var gc=/[<\u2028\u2029]/g;
-function hc(a){return JSON.stringify(a).replace(gc,function(b){switch(b){case "<":return"\\u003c";case "\u2028":return"\\u2028";case "\u2029":return"\\u2029";default:throw Error("escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}})}var ic=/[&><\u2028\u2029]/g;
-function jc(a){return JSON.stringify(a).replace(ic,function(b){switch(b){case "&":return"\\u0026";case ">":return"\\u003e";case "<":return"\\u003c";case "\u2028":return"\\u2028";case "\u2029":return"\\u2029";default:throw Error("escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}})}var kc=!1,lc=!0;
-function mc(a){var b=a.rules,c=a.hrefs,d=0;if(c.length){this.push('");kc=!0;b.length=0;c.length=0}}function nc(a){return 2!==a.state?kc=!0:!1}function oc(a,b,c){kc=!1;lc=!0;b.styles.forEach(mc,a);b.stylesheets.forEach(nc);kc&&(c.stylesToHoist=!0);return lc}
-function M(a){for(var b=0;b');for(a=0;a");c.length=0;d.length=0}}
-function sc(a){if(0===a.state){a.state=1;var b=a.props;K(pc,{rel:"preload",as:"style",href:a.props.href,crossOrigin:b.crossOrigin,fetchPriority:b.fetchPriority,integrity:b.integrity,media:b.media,hrefLang:b.hrefLang,referrerPolicy:b.referrerPolicy});for(a=0;a; rel=dns-prefetch",2<=(c.remainingCapacity-=e.length));f?(d.resets.dns[a]=null,c.preconnects&&(c.preconnects+=", "),c.preconnects+=e):(e=[],K(e,{href:a,rel:"dns-prefetch"}),d.preconnects.add(e))}yc(b)}}}
-function fb(a,b){var c=O?O:null;if(c){var d=c.resumableState,e=c.renderState;if("string"===typeof a&&a){var f="use-credentials"===b?"credentials":"string"===typeof b?"anonymous":"default";if(!d.connectResources[f].hasOwnProperty(a)){d.connectResources[f][a]=null;d=e.headers;var g,h;if(h=d&&0; rel=preconnect";if("string"===typeof b){var k=(""+b).replace(zc,Ac);h+='; crossorigin="'+k+'"'}h=(g=h,2<=(d.remainingCapacity-=g.length))}h?(e.resets.connect[f][a]=
-null,d.preconnects&&(d.preconnects+=", "),d.preconnects+=g):(f=[],K(f,{rel:"preconnect",href:a,crossOrigin:b}),e.preconnects.add(f))}yc(c)}}}
-function gb(a,b,c){var d=O?O:null;if(d){var e=d.resumableState,f=d.renderState;if(b&&a){switch(b){case "image":if(c){var g=c.imageSrcSet;var h=c.imageSizes;var k=c.fetchPriority}var l=g?g+"\n"+(h||""):a;if(e.imageResources.hasOwnProperty(l))return;e.imageResources[l]=y;e=f.headers;var n;e&&0; rel=preload; as="'+b+'"';for(var d in c)w.call(c,d)&&(a=c[d],"string"===typeof a&&(b+="; "+d.toLowerCase()+'="'+(""+a).replace(zc,Ac)+'"'));return b}var wc=/[<>\r\n]/g;
-function xc(a){switch(a){case "<":return"%3C";case ">":return"%3E";case "\n":return"%0A";case "\r":return"%0D";default:throw Error("escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}}var zc=/["';,\r\n]/g;
-function Ac(a){switch(a){case '"':return"%22";case "'":return"%27";case ";":return"%3B";case ",":return"%2C";case "\n":return"%0A";case "\r":return"%0D";default:throw Error("escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}}function Bc(a){this.styles.add(a)}function Cc(a){this.stylesheets.add(a)}
-function Dc(a,b,c){if(b=a.onHeaders){var d=a.headers;if(d){var e=d.preconnects;d.fontPreloads&&(e&&(e+=", "),e+=d.fontPreloads);d.highImagePreloads&&(e&&(e+=", "),e+=d.highImagePreloads);if(!c){c=a.styles.values();var f=c.next();a:for(;0",htmlChunks:null,headChunks:null,externalRuntimeScript:null,bootstrapChunks:[],onHeaders:void 0,headers:null,resets:{font:{},dns:{},connect:{default:{},anonymous:{},credentials:{}},image:{},style:{}},
-charsetChunks:[],preconnectChunks:[],importMapChunks:[],preloadChunks:[],hoistableChunks:[],preconnects:e,fontPreloads:f,highImagePreloads:g,styles:h,bootstrapScripts:k,scripts:l,bulkPreloads:n,preloads:q,boundaryResources:null,stylesToHoist:!1,generateStaticMarkup:b}}function Fc(a,b,c,d){if(c.generateStaticMarkup)return a.push(x(b)),!1;""===b?a=d:(d&&a.push("\x3c!-- --\x3e"),a.push(x(b)),a=!0);return a}
-var Gc=Symbol.for("react.element"),Hc=Symbol.for("react.portal"),Ic=Symbol.for("react.fragment"),Jc=Symbol.for("react.strict_mode"),Kc=Symbol.for("react.profiler"),Lc=Symbol.for("react.provider"),Mc=Symbol.for("react.context"),Nc=Symbol.for("react.server_context"),Oc=Symbol.for("react.forward_ref"),Pc=Symbol.for("react.suspense"),Qc=Symbol.for("react.suspense_list"),Rc=Symbol.for("react.memo"),md=Symbol.for("react.lazy"),nd=Symbol.for("react.scope"),od=Symbol.for("react.debug_trace_mode"),pd=Symbol.for("react.offscreen"),
-qd=Symbol.for("react.legacy_hidden"),rd=Symbol.for("react.cache"),sd=Symbol.for("react.default_value"),td=Symbol.for("react.memo_cache_sentinel"),ud=Symbol.for("react.postpone"),vd=Symbol.iterator;
-function wd(a){if(null==a)return null;if("function"===typeof a)return a.displayName||a.name||null;if("string"===typeof a)return a;switch(a){case Ic:return"Fragment";case Hc:return"Portal";case Kc:return"Profiler";case Jc:return"StrictMode";case Pc:return"Suspense";case Qc:return"SuspenseList";case rd:return"Cache"}if("object"===typeof a)switch(a.$$typeof){case Mc:return(a.displayName||"Context")+".Consumer";case Lc:return(a._context.displayName||"Context")+".Provider";case Oc:var b=a.render;a=a.displayName;
-a||(a=b.displayName||b.name||"",a=""!==a?"ForwardRef("+a+")":"ForwardRef");return a;case Rc:return b=a.displayName||null,null!==b?b:wd(a.type)||"Memo";case md:b=a._payload;a=a._init;try{return wd(a(b))}catch(c){break}case Nc:return(a.displayName||a._globalName)+".Provider"}return null}var xd={};function yd(a,b){a=a.contextTypes;if(!a)return xd;var c={},d;for(d in a)c[d]=b[d];return c}var zd=null;
-function Ad(a,b){if(a!==b){a.context._currentValue2=a.parentValue;a=a.parent;var c=b.parent;if(null===a){if(null!==c)throw Error("The stacks must reach the root at the same time. This is a bug in React.");}else{if(null===c)throw Error("The stacks must reach the root at the same time. This is a bug in React.");Ad(a,c)}b.context._currentValue2=b.value}}function Bd(a){a.context._currentValue2=a.parentValue;a=a.parent;null!==a&&Bd(a)}
-function Cd(a){var b=a.parent;null!==b&&Cd(b);a.context._currentValue2=a.value}function Dd(a,b){a.context._currentValue2=a.parentValue;a=a.parent;if(null===a)throw Error("The depth must equal at least at zero before reaching the root. This is a bug in React.");a.depth===b.depth?Ad(a,b):Dd(a,b)}
-function Ed(a,b){var c=b.parent;if(null===c)throw Error("The depth must equal at least at zero before reaching the root. This is a bug in React.");a.depth===c.depth?Ad(a,c):Ed(a,c);b.context._currentValue2=b.value}function Fd(a){var b=zd;b!==a&&(null===b?Cd(a):null===a?Bd(b):b.depth===a.depth?Ad(b,a):b.depth>a.depth?Dd(b,a):Ed(b,a),zd=a)}
-var Gd={isMounted:function(){return!1},enqueueSetState:function(a,b){a=a._reactInternals;null!==a.queue&&a.queue.push(b)},enqueueReplaceState:function(a,b){a=a._reactInternals;a.replace=!0;a.queue=[b]},enqueueForceUpdate:function(){}};
-function Hd(a,b,c,d){var e=void 0!==a.state?a.state:null;a.updater=Gd;a.props=c;a.state=e;var f={queue:[],replace:!1};a._reactInternals=f;var g=b.contextType;a.context="object"===typeof g&&null!==g?g._currentValue2:d;g=b.getDerivedStateFromProps;"function"===typeof g&&(g=g(c,e),e=null===g||void 0===g?e:r({},e,g),a.state=e);if("function"!==typeof b.getDerivedStateFromProps&&"function"!==typeof a.getSnapshotBeforeUpdate&&("function"===typeof a.UNSAFE_componentWillMount||"function"===typeof a.componentWillMount))if(b=
-a.state,"function"===typeof a.componentWillMount&&a.componentWillMount(),"function"===typeof a.UNSAFE_componentWillMount&&a.UNSAFE_componentWillMount(),b!==a.state&&Gd.enqueueReplaceState(a,a.state,null),null!==f.queue&&0>=g;e-=g;return{id:1<<32-Kd(b)+e|c<>>=0;return 0===a?32:31-(Md(a)/Nd|0)|0}var Od=Error("Suspense Exception: This is not a real error! It's an implementation detail of `use` to interrupt the current render. You must either rethrow it immediately, or move the `use` call outside of the `try/catch` block. Capturing without rethrowing will lead to unexpected behavior.\n\nTo handle async errors, wrap your component in an error boundary, or call the promise's `.catch` method and pass the result to `use`");
-function Pd(){}function Qd(a,b,c){c=a[c];void 0===c?a.push(b):c!==b&&(b.then(Pd,Pd),b=c);switch(b.status){case "fulfilled":return b.value;case "rejected":throw b.reason;default:if("string"!==typeof b.status)switch(a=b,a.status="pending",a.then(function(d){if("pending"===b.status){var e=b;e.status="fulfilled";e.value=d}},function(d){if("pending"===b.status){var e=b;e.status="rejected";e.reason=d}}),b.status){case "fulfilled":return b.value;case "rejected":throw b.reason;}Rd=b;throw Od;}}var Rd=null;
-function Sd(){if(null===Rd)throw Error("Expected a suspended thenable. This is a bug in React. Please file an issue.");var a=Rd;Rd=null;return a}function Td(a,b){return a===b&&(0!==a||1/a===1/b)||a!==a&&b!==b}var Ud="function"===typeof Object.is?Object.is:Td,R=null,Vd=null,Wd=null,Xd=null,Yd=null,S=null,Zd=!1,$d=!1,ae=0,be=0,ce=-1,de=0,ee=null,fe=null,ge=0;
-function he(){if(null===R)throw Error("Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.");return R}
-function ie(){if(0=h.insertionMode){a.hasBody=!0;break a}break;case "html":if(0===h.insertionMode){a.hasHtml=!0;break a}}b.push(Mb(e))}d.lastPushedText=!1}else{switch(e){case qd:case od:case Jc:case Kc:case Ic:e=b.keyPath;b.keyPath=c;X(a,b,null,f.children,-1);b.keyPath=e;return;case pd:"hidden"!==f.mode&&(e=b.keyPath,b.keyPath=c,X(a,b,null,f.children,-1),b.keyPath=e);return;case Qc:e=b.keyPath;b.keyPath=c;X(a,b,null,f.children,-1);b.keyPath=e;return;case nd:throw Error("ReactDOMServer does not yet support scope components.");
-case Pc:a:if(null!==b.replay){e=b.keyPath;b.keyPath=c;c=f.children;try{Y(a,b,c,-1)}finally{b.keyPath=e}}else{l=b.keyPath;e=b.blockedBoundary;var n=b.blockedSegment;d=f.fallback;var q=f.children;f=new Set;g=Ke(a,f);null!==a.trackedPostpones&&(g.trackedContentKeyPath=c);k=Ge(a,n.chunks.length,g,b.formatContext,!1,!1);n.children.push(k);n.lastPushedText=!1;var m=Ge(a,0,null,b.formatContext,!1,!1);m.parentFlushed=!0;b.blockedBoundary=g;b.blockedSegment=m;a.renderState.boundaryResources=g.resources;b.keyPath=
-c;try{if(Y(a,b,q,-1),a.renderState.generateStaticMarkup||m.lastPushedText&&m.textEmbedded&&m.chunks.push("\x3c!-- --\x3e"),m.status=1,Re(g,m),0===g.pendingTasks&&0===g.status){g.status=1;break a}}catch(B){m.status=4,g.status=4,"object"===typeof B&&null!==B&&B.$$typeof===ud?(a.onPostpone(B.message),h="POSTPONE"):h=W(a,B),g.errorDigest=h}finally{a.renderState.boundaryResources=e?e.resources:null,b.blockedBoundary=e,b.blockedSegment=n,b.keyPath=l}h=[c[0],"Suspense Fallback",c[2]];l=a.trackedPostpones;
-null!==l&&(n=[h[1],h[2],[],null],l.workingMap.set(h,n),5===g.status?l.workingMap.get(c)[4]=n:g.trackedFallbackNode=n);b=He(a,null,d,-1,e,k,f,h,b.formatContext,b.legacyContext,b.context,b.treeContext);a.pingedTasks.push(b)}return}if("object"===typeof e&&null!==e)switch(e.$$typeof){case Oc:e=e.render;R={};Vd=b;Wd=a;Xd=c;be=ae=0;ce=-1;de=0;ee=d;d=e(f,g);f=ke(e,f,d,g);Oe(a,b,c,f,0!==ae,be,ce);return;case Rc:e=e.type;f=Pe(e,f);Qe(a,b,c,d,e,f,g);return;case Lc:h=f.children;d=b.keyPath;e=e._context;f=f.value;
-g=e._currentValue2;e._currentValue2=f;k=zd;zd=f={parent:k,depth:null===k?0:k.depth+1,context:e,parentValue:g,value:f};b.context=f;b.keyPath=c;X(a,b,null,h,-1);a=zd;if(null===a)throw Error("Tried to pop a Context at the root of the app. This is a bug in React.");c=a.parentValue;a.context._currentValue2=c===sd?a.context._defaultValue:c;a=zd=a.parent;b.context=a;b.keyPath=d;return;case Mc:f=f.children;f=f(e._currentValue2);e=b.keyPath;b.keyPath=c;X(a,b,null,f,-1);b.keyPath=e;return;case md:h=e._init;
-e=h(e._payload);f=Pe(e,f);Qe(a,b,c,d,e,f,void 0);return}throw Error("Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: "+((null==e?e:typeof e)+"."));}}
-function Se(a,b,c,d,e){var f=b.replay,g=b.blockedBoundary,h=Ge(a,0,null,b.formatContext,!1,!1);h.id=c;h.parentFlushed=!0;try{b.replay=null,b.blockedSegment=h,Y(a,b,d,e),h.status=1,null===g?a.completedRootSegment=h:(Re(g,h),g.parentFlushed&&a.partialBoundaries.push(g))}finally{b.replay=f,b.blockedSegment=null}}
-function X(a,b,c,d,e){if(null!==b.replay&&"number"===typeof b.replay.slots)Se(a,b,b.replay.slots,d,e);else{b.node=d;b.childIndex=e;if("object"===typeof d&&null!==d){switch(d.$$typeof){case Gc:var f=d.type,g=d.key,h=d.props,k=d.ref,l=wd(f),n=null==g?-1===e?0:e:g;g=[b.keyPath,l,n];if(null!==b.replay)a:{var q=b.replay;e=q.nodes;for(d=0;d in this slot but instead it rendered <"+
-l+">. The tree doesn't match so React will fallback to client rendering.");l=m[2];m=m[3];n=b.node;b.replay={nodes:l,slots:m,pendingTasks:1};try{Qe(a,b,g,c,f,h,k);if(1===b.replay.pendingTasks&&0 in this slot but instead it rendered <"+(wd(f)||"Unknown")+">. The tree doesn't match so React will fallback to client rendering.");b:{c=void 0;f=m[5];k=m[2];q=m[3];l=null===m[4]?[]:m[4][2];m=null===m[4]?null:m[4][3];n=b.keyPath;var B=b.replay,C=b.blockedBoundary,P=h.children;h=h.fallback;var u=new Set,z=Ke(a,u);z.parentFlushed=!0;z.rootSegmentID=f;b.blockedBoundary=z;b.replay={nodes:k,slots:q,
-pendingTasks:1};a.renderState.boundaryResources=z.resources;try{Y(a,b,P,-1);if(1===b.replay.pendingTasks&&0');case 1:c.status=2;var e=!0;d=c.chunks;var f=0;c=c.children;for(var g=0;g");case 3:return a.push(" ");case 4:return a.push("");case 5:return a.push("");case 6:return a.push("");case 7:return a.push("");case 8:return a.push("");default:throw Error("Unknown insertion mode. This is a bug in React.");}}var ic=/[<\u2028\u2029]/g;
+function jc(a){return JSON.stringify(a).replace(ic,function(b){switch(b){case "<":return"\\u003c";case "\u2028":return"\\u2028";case "\u2029":return"\\u2029";default:throw Error("escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}})}var kc=/[&><\u2028\u2029]/g;
+function lc(a){return JSON.stringify(a).replace(kc,function(b){switch(b){case "&":return"\\u0026";case ">":return"\\u003e";case "<":return"\\u003c";case "\u2028":return"\\u2028";case "\u2029":return"\\u2029";default:throw Error("escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}})}var mc=!1,nc=!0;
+function oc(a){var b=a.rules,c=a.hrefs,d=0;if(c.length){this.push('");mc=!0;b.length=0;c.length=0}}function pc(a){return 2!==a.state?mc=!0:!1}function qc(a,b,c){mc=!1;nc=!0;b.styles.forEach(oc,a);b.stylesheets.forEach(pc);mc&&(c.stylesToHoist=!0);return nc}
+function O(a){for(var b=0;b
');for(a=0;a");c.length=0;d.length=0}}
+function uc(a){if(0===a.state){a.state=1;var b=a.props;M(rc,{rel:"preload",as:"style",href:a.props.href,crossOrigin:b.crossOrigin,fetchPriority:b.fetchPriority,integrity:b.integrity,media:b.media,hrefLang:b.hrefLang,referrerPolicy:b.referrerPolicy});for(a=0;a; rel=dns-prefetch",2<=(c.remainingCapacity-=e.length));f?(d.resets.dns[a]=null,c.preconnects&&(c.preconnects+=", "),c.preconnects+=e):(e=[],M(e,{href:a,rel:"dns-prefetch"}),d.preconnects.add(e))}Ac(b)}}}
+function fb(a,b){var c=R?R:null;if(c){var d=c.resumableState,e=c.renderState;if("string"===typeof a&&a){var f="use-credentials"===b?"credentials":"string"===typeof b?"anonymous":"default";if(!d.connectResources[f].hasOwnProperty(a)){d.connectResources[f][a]=null;d=e.headers;var g,h;if(h=d&&0; rel=preconnect";if("string"===typeof b){var k=(""+b).replace(Bc,Cc);h+='; crossorigin="'+k+'"'}h=(g=h,2<=(d.remainingCapacity-=g.length))}h?(e.resets.connect[f][a]=
+null,d.preconnects&&(d.preconnects+=", "),d.preconnects+=g):(f=[],M(f,{rel:"preconnect",href:a,crossOrigin:b}),e.preconnects.add(f))}Ac(c)}}}
+function gb(a,b,c){var d=R?R:null;if(d){var e=d.resumableState,f=d.renderState;if(b&&a){switch(b){case "image":if(c){var g=c.imageSrcSet;var h=c.imageSizes;var k=c.fetchPriority}var l=g?g+"\n"+(h||""):a;if(e.imageResources.hasOwnProperty(l))return;e.imageResources[l]=A;e=f.headers;var n;e&&0; rel=preload; as="'+b+'"';for(var d in c)y.call(c,d)&&(a=c[d],"string"===typeof a&&(b+="; "+d.toLowerCase()+'="'+(""+a).replace(Bc,Cc)+'"'));return b}var yc=/[<>\r\n]/g;
+function zc(a){switch(a){case "<":return"%3C";case ">":return"%3E";case "\n":return"%0A";case "\r":return"%0D";default:throw Error("escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}}var Bc=/["';,\r\n]/g;
+function Cc(a){switch(a){case '"':return"%22";case "'":return"%27";case ";":return"%3B";case ",":return"%2C";case "\n":return"%0A";case "\r":return"%0D";default:throw Error("escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}}function Dc(a){this.styles.add(a)}function Ec(a){this.stylesheets.add(a)}
+function Fc(a,b,c){if(b=a.onHeaders){var d=a.headers;if(d){var e=d.preconnects;d.fontPreloads&&(e&&(e+=", "),e+=d.fontPreloads);d.highImagePreloads&&(e&&(e+=", "),e+=d.highImagePreloads);if(!c){c=a.styles.values();var f=c.next();a:for(;0",(""+e).replace(mb,nb),"\x3c/script>");e=c+"P:";var h=c+"S:";c+="B:";var k=new Set,l=new Set,n=new Set,r=new Map,m=new Set,B=new Set,E=new Set,P={images:new Map,stylesheets:new Map,scripts:new Map,moduleScripts:new Map};if(void 0!==f)for(var v=0;v\x3c/script>')}if(void 0!==g)for(f=0;f\x3c/script>');return{placeholderPrefix:e,segmentPrefix:h,boundaryPrefix:c,startInlineScript:"');
+const startScriptSrc = stringToPrecomputedChunk('');
+/**
+ * This escaping function is designed to work with bootstrapScriptContent and importMap only.
+ * because we know we are escaping the entire script. We can avoid for instance
+ * escaping html comment string sequences that are valid javascript as well because
+ * if there are no sebsequent '); // Since we store headers as strings we deal with their length in utf16 code units
+// rather than visual characters or the utf8 encoding that is used for most binary
+// serialization. Some common HTTP servers only allow for headers to be 4kB in length.
+// We choose a default length that is likely to be well under this already limited length however
+// pathological cases may still cause the utf-8 encoding of the headers to approach this limit.
+// It should also be noted that this maximum is a soft maximum. we have not reached the limit we will
+// allow one more header to be captured which means in practice if the limit is approached it will be exceeded
+
+const DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep track of what we've already written so we can refer back to it.
+// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
+// is set, the server will send instructions via data attributes (instead of inline scripts)
+
+function createRenderState(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+ const inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const completeSegmentData1 = stringToPrecomputedChunk('');
+const completeBoundaryData1 = stringToPrecomputedChunk('');
+const clientRenderData1 = stringToPrecomputedChunk('
+ return writeChunkAndReturn(destination, clientRenderDataEnd);
+ }
+}
+const regexForJSStringsInInstructionScripts = /[<\u2028\u2029]/g;
+
+function escapeJSStringsForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInInstructionScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const regexForJSStringsInScripts = /[&><\u2028\u2029]/g;
+
+function escapeJSObjectForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '&':
+ return '\\u0026';
+
+ case '>':
+ return '\\u003e';
+
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(''); // Tracks whether the boundary currently flushing is flushign style tags or has any
+// stylesheet dependencies not flushed in the Preamble.
+
+let currentlyRenderingBoundaryHasStylesToHoist = false; // Acts as a return value for the forEach execution of style tag flushing.
+
+let destinationHasCapacity = true;
+
+function flushStyleTagsLateForBoundary(styleQueue) {
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs;
+
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, lateStyleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ writeChunk(this, lateStyleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, lateStyleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ destinationHasCapacity = writeChunkAndReturn(this, lateStyleTagTemplateClose); // We wrote style tags for this boundary and we may need to emit a script
+ // to hoist them.
+
+ currentlyRenderingBoundaryHasStylesToHoist = true; // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function hasStylesToHoist(stylesheet) {
+ // We need to reveal boundaries with styles whenever a stylesheet it depends on is either
+ // not flushed or flushed after the preamble (shell).
+ if (stylesheet.state !== PREAMBLE) {
+ currentlyRenderingBoundaryHasStylesToHoist = true;
+ return true;
+ }
+
+ return false;
+}
+
+function writeResourcesForBoundary(destination, boundaryResources, renderState) {
+ // Reset these on each invocation, they are only safe to read in this function
+ currentlyRenderingBoundaryHasStylesToHoist = false;
+ destinationHasCapacity = true; // Flush style tags for each precedence this boundary depends on
+
+ boundaryResources.styles.forEach(flushStyleTagsLateForBoundary, destination); // Determine if this boundary has stylesheets that need to be awaited upon completion
+
+ boundaryResources.stylesheets.forEach(hasStylesToHoist);
+
+ if (currentlyRenderingBoundaryHasStylesToHoist) {
+ renderState.stylesToHoist = true;
+ }
+
+ return destinationHasCapacity;
+}
+
+function flushResource(resource) {
+ for (let i = 0; i < resource.length; i++) {
+ writeChunk(this, resource[i]);
+ }
+
+ resource.length = 0;
+}
+
+const stylesheetFlushingQueue = [];
+
+function flushStyleInPreamble(stylesheet, key, map) {
+ // We still need to encode stylesheet chunks
+ // because unlike most Hoistables and Resources we do not eagerly encode
+ // them during render. This is because if we flush late we have to send a
+ // different encoding and we don't want to encode multiple times
+ pushLinkImpl(stylesheetFlushingQueue, stylesheet.props);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ stylesheet.state = PREAMBLE;
+}
+
+const styleTagResourceOpen1 = stringToPrecomputedChunk('');
+
+function flushStylesInPreamble(styleQueue, precedence) {
+ const hasStylesheets = styleQueue.sheets.size > 0;
+ styleQueue.sheets.forEach(flushStyleInPreamble, this);
+ styleQueue.sheets.clear();
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs; // If we don't emit any stylesheets at this precedence we still need to maintain the precedence
+ // order so even if there are no rules for style tags at this precedence we emit an empty style
+ // tag with the data-precedence attribute
+
+ if (!hasStylesheets || hrefs.length) {
+ writeChunk(this, styleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, styleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ }
+
+ writeChunk(this, styleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ writeChunk(this, styleTagResourceClose); // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function preloadLateStyle(stylesheet) {
+ if (stylesheet.state === PENDING$1) {
+ stylesheet.state = PRELOADED;
+ const preloadProps = preloadAsStylePropsFromProps(stylesheet.props.href, stylesheet.props);
+ pushLinkImpl(stylesheetFlushingQueue, preloadProps);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ }
+}
+
+function preloadLateStyles(styleQueue) {
+ styleQueue.sheets.forEach(preloadLateStyle, this);
+ styleQueue.sheets.clear();
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+
+function writePreamble(destination, resumableState, renderState, willFlushAllSegments) {
+ // This function must be called exactly once on every request
+ if (!willFlushAllSegments && renderState.externalRuntimeScript) {
+ // If the root segment is incomplete due to suspended tasks
+ // (e.g. willFlushAllSegments = false) and we are using data
+ // streaming format, ensure the external runtime is sent.
+ // (User code could choose to send this even earlier by calling
+ // preinit(...), if they know they will suspend).
+ const _renderState$external = renderState.externalRuntimeScript,
+ src = _renderState$external.src,
+ chunks = _renderState$external.chunks;
+ internalPreinitScript(resumableState, renderState, src, chunks);
+ }
+
+ const htmlChunks = renderState.htmlChunks;
+ const headChunks = renderState.headChunks;
+ let i = 0; // Emit open tags before Hoistables and Resources
+
+ if (htmlChunks) {
+ // We have an to emit as part of the preamble
+ for (i = 0; i < htmlChunks.length; i++) {
+ writeChunk(destination, htmlChunks[i]);
+ }
+
+ if (headChunks) {
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } else {
+ // We did not render a head but we emitted an so we emit one now
+ writeChunk(destination, startChunkForTag('head'));
+ writeChunk(destination, endOfStartTag);
+ }
+ } else if (headChunks) {
+ // We do not have an but we do have a
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } // Emit high priority Hoistables
+
+
+ const charsetChunks = renderState.charsetChunks;
+
+ for (i = 0; i < charsetChunks.length; i++) {
+ writeChunk(destination, charsetChunks[i]);
+ }
+
+ charsetChunks.length = 0; // emit preconnect resources
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Flush unblocked stylesheets by precedence
+
+ renderState.styles.forEach(flushStylesInPreamble, destination);
+ const importMapChunks = renderState.importMapChunks;
+
+ for (i = 0; i < importMapChunks.length; i++) {
+ writeChunk(destination, importMapChunks[i]);
+ }
+
+ importMapChunks.length = 0;
+ renderState.bootstrapScripts.forEach(flushResource, destination);
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0; // Flush closing head if necessary
+
+ if (htmlChunks && headChunks === null) {
+ // We have an rendered but no rendered. We however inserted
+ // a up above so we need to emit the now. This is safe because
+ // if the main content contained the it would also have provided a
+ // . This means that all the content inside is either or
+ // invalid HTML
+ writeChunk(destination, endChunkForTag('head'));
+ }
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+function writeHoistables(destination, resumableState, renderState) {
+ let i = 0; // Emit high priority Hoistables
+ // We omit charsetChunks because we have already sent the shell and if it wasn't
+ // already sent it is too late now.
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Preload any stylesheets. these will emit in a render instruction that follows this
+ // but we want to kick off preloading as soon as possible
+
+ renderState.styles.forEach(preloadLateStyles, destination); // We only hoist importmaps that are configured through createResponse and that will
+ // always flush in the preamble. Generally we don't expect people to render them as
+ // tags when using React but if you do they are going to be treated like regular inline
+ // scripts and flush after other hoistables which is problematic
+ // bootstrap scripts should flush above script priority but these can only flush in the preamble
+ // so we elide the code here for performance
+
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0;
+}
+function writePostamble(destination, resumableState) {
+ if (resumableState.hasBody) {
+ writeChunk(destination, endChunkForTag('body'));
+ }
+
+ if (resumableState.hasHtml) {
+ writeChunk(destination, endChunkForTag('html'));
+ }
+}
+const arrayFirstOpenBracket = stringToPrecomputedChunk('[');
+const arraySubsequentOpenBracket = stringToPrecomputedChunk(',[');
+const arrayInterstitial = stringToPrecomputedChunk(',');
+const arrayCloseBracket = stringToPrecomputedChunk(']'); // This function writes a 2D array of strings to be embedded in javascript.
+// E.g.
+// [["JS_escaped_string1", "JS_escaped_string2"]]
+
+function writeStyleResourceDependenciesInJS(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInJS(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInJS(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInJS(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+}
+
+function writeStyleResourceDependencyInJS(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedPrecedence)));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw Error(formatProdErrorMessage(399, 'link'));
+
+ default:
+ writeStyleResourceAttributeInJS(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInJS(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeName)));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeValue)));
+} // This function writes a 2D array of strings to be embedded in an attribute
+// value and read with JSON.parse in ReactDOMServerExternalRuntime.js
+// E.g.
+// [["JSON_escaped_string1", "JSON_escaped_string2"]]
+
+
+function writeStyleResourceDependenciesInAttr(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInAttr(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInAttr(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInAttr(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+}
+
+function writeStyleResourceDependencyInAttr(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedPrecedence))));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw Error(formatProdErrorMessage(399, 'link'));
+
+ default:
+ writeStyleResourceAttributeInAttr(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInAttr(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeName))));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeValue))));
+}
+/**
+ * Resources
+ */
+
+
+const PENDING$1 = 0;
+const PRELOADED = 1;
+const PREAMBLE = 2;
+const LATE = 3;
+function createBoundaryResources() {
+ return {
+ styles: new Set(),
+ stylesheets: new Set()
+ };
+}
+function setCurrentlyRenderingBoundaryResourcesTarget(renderState, boundaryResources) {
+ renderState.boundaryResources = boundaryResources;
+}
+
+function getResourceKey(href) {
+ return href;
+}
+
+function getImageResourceKey(href, imageSrcSet, imageSizes) {
+ if (imageSrcSet) {
+ return imageSrcSet + '\n' + (imageSizes || '');
+ }
+
+ return href;
+}
+
+function prefetchDNS(href) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const key = getResourceKey(href);
+
+ if (!resumableState.dnsResources.hasOwnProperty(key)) {
+ resumableState.dnsResources[key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPrefetchDNSAsHeader(href), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this as resettable in case we are prerendering and postpone in the Shell
+ renderState.resets.dns[key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ // Encode as element
+ const resource = [];
+ pushLinkImpl(resource, {
+ href,
+ rel: 'dns-prefetch'
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preconnect(href, crossOrigin) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const bucket = crossOrigin === 'use-credentials' ? 'credentials' : typeof crossOrigin === 'string' ? 'anonymous' : 'default';
+ const key = getResourceKey(href);
+
+ if (!resumableState.connectResources[bucket].hasOwnProperty(key)) {
+ resumableState.connectResources[bucket][key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreconnectAsHeader(href, crossOrigin), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this in resettableState in case we are prerending and postpone in the Shell
+ renderState.resets.connect[bucket][key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ const resource = [];
+ pushLinkImpl(resource, {
+ rel: 'preconnect',
+ href,
+ crossOrigin
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preload(href, as, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (as && href) {
+ switch (as) {
+ case 'image':
+ {
+ let imageSrcSet, imageSizes, fetchPriority;
+
+ if (options) {
+ imageSrcSet = options.imageSrcSet;
+ imageSizes = options.imageSizes;
+ fetchPriority = options.fetchPriority;
+ }
+
+ const key = getImageResourceKey(href, imageSrcSet, imageSizes);
+
+ if (resumableState.imageResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resumableState.imageResources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && fetchPriority === 'high' && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit a preload as a header so we
+ // track this to make sure we don't reset it.
+ renderState.resets.image[key] = PRELOAD_NO_CREDS;
+
+ if (headers.highImagePreloads) {
+ headers.highImagePreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.highImagePreloads += header;
+ } else {
+ // If we don't have headers to write to we have to encode as elements to flush in the head
+ // When we have imageSrcSet the browser probably cannot load the right version from headers
+ // (this should be verified by testing). For now we assume these need to go in the head
+ // as elements even if headers are available.
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ // There is a bug in Safari where imageSrcSet is not respected on preload links
+ // so we omit the href here if we have imageSrcSet b/c safari will load the wrong image.
+ // This harms older browers that do not support imageSrcSet by making their preloads not work
+ // but this population is shrinking fast and is already small so we accept this tradeoff.
+ href: imageSrcSet ? undefined : href,
+ as
+ }, options));
+
+ if (fetchPriority === 'high') {
+ renderState.highImagePreloads.add(resource);
+ } else {
+ renderState.bulkPreloads.add(resource); // Stash the resource in case we need to promote it to higher priority
+ // when an img tag is rendered
+
+ renderState.preloads.images.set(key, resource);
+ }
+ }
+
+ break;
+ }
+
+ case 'style':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.styleResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.styleResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.stylesheets.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ break;
+ }
+
+ case 'script':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.scriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ renderState.preloads.scripts.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.scriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ break;
+ }
+
+ default:
+ {
+ const key = getResourceKey(href);
+ const hasAsType = resumableState.unknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.unknownResources[as] = resources;
+ }
+
+ resources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && as === 'font' && ( // We compute the header here because we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit this preload so we
+ // track it here to prevent it from being reset.
+ renderState.resets.font[key] = PRELOAD_NO_CREDS;
+
+ if (headers.fontPreloads) {
+ headers.fontPreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.fontPreloads += header;
+ } else {
+ // We either don't have headers or we are preloading something that does
+ // not warrant elevated priority so we encode as an element.
+ const resource = [];
+
+ const props = assign({
+ rel: 'preload',
+ href,
+ as
+ }, options);
+
+ pushLinkImpl(resource, props);
+
+ switch (as) {
+ case 'font':
+ renderState.fontPreloads.add(resource);
+ break;
+ // intentional fall through
+
+ default:
+ renderState.bulkPreloads.add(resource);
+ }
+ }
+ }
+ } // If we got this far we created a new resource
+
+
+ flushResources(request);
+ }
+}
+
+function preloadModule(href, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ const key = getResourceKey(href);
+ const as = options && typeof options.as === 'string' ? options.as : 'script';
+ let resource;
+
+ switch (as) {
+ case 'script':
+ {
+ if (resumableState.moduleScriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resource = [];
+ resumableState.moduleScriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.moduleScripts.set(key, resource);
+ break;
+ }
+
+ default:
+ {
+ const hasAsType = resumableState.moduleUnknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.moduleUnknownResources[as] = resources;
+ }
+
+ resource = [];
+ resources[key] = PRELOAD_NO_CREDS;
+ }
+ }
+
+ pushLinkImpl(resource, assign({
+ rel: 'modulepreload',
+ href
+ }, options));
+ renderState.bulkPreloads.add(resource); // If we got this far we created a new resource
+
+ flushResources(request);
+ }
+}
+
+function preinitStyle(href, precedence, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ precedence = precedence || 'default';
+ const key = getResourceKey(href);
+ let styleQueue = renderState.styles.get(precedence);
+ const hasKey = resumableState.styleResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.styleResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.styleResources[key] = EXISTS; // If this is the first time we've encountered this precedence we need
+ // to create a StyleQueue
+
+ if (!styleQueue) {
+ styleQueue = {
+ precedence: stringToChunk(escapeTextForBrowser(precedence)),
+ rules: [],
+ hrefs: [],
+ sheets: new Map()
+ };
+ renderState.styles.set(precedence, styleQueue);
+ }
+
+ const resource = {
+ state: PENDING$1,
+ props: assign({
+ rel: 'stylesheet',
+ href,
+ 'data-precedence': precedence
+ }, options)
+ };
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(resource.props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.stylesheets.get(key);
+
+ if (preloadResource && preloadResource.length > 0) {
+ // The Preload for this resource was created in this render pass and has not flushed yet so
+ // we need to clear it to avoid it flushing.
+ preloadResource.length = 0;
+ } else {
+ // Either the preload resource from this render already flushed in this render pass
+ // or the preload flushed in a prior pass (prerender). In either case we need to mark
+ // this resource as already having been preloaded.
+ resource.state = PRELOADED;
+ }
+ } // We add the newly created resource to our StyleQueue and if necessary
+ // track the resource with the currently rendering boundary
+
+
+ styleQueue.sheets.set(key, resource); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+ }
+}
+
+function preinitScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.scriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.scriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.scriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.scripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+}
+
+function preinitModuleScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.moduleScriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.moduleScriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.moduleScriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ type: 'module',
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.moduleScripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+} // This function is only safe to call at Request start time since it assumes
+// that each module has not already been preloaded. If we find a need to preload
+// scripts at any other point in time we will need to check whether the preload
+// already exists and not assume it
+
+
+function preloadBootstrapScriptOrModule(resumableState, renderState, href, props) {
+
+ const key = getResourceKey(href);
+ // used to preinit the resource. If a script can be preinited then it shouldn't
+ // be a bootstrap script/module and if it is a bootstrap script/module then it
+ // must not be safe to emit early. To avoid possibly allowing for preinits of
+ // bootstrap scripts/modules we occlude these keys.
+
+
+ resumableState.scriptResources[key] = EXISTS;
+ resumableState.moduleScriptResources[key] = EXISTS;
+ const resource = [];
+ pushLinkImpl(resource, props);
+ renderState.bootstrapScripts.add(resource);
+}
+
+function internalPreinitScript(resumableState, renderState, src, chunks) {
+ const key = getResourceKey(src);
+
+ if (!resumableState.scriptResources.hasOwnProperty(key)) {
+ const resource = chunks;
+ resumableState.scriptResources[key] = EXISTS;
+ renderState.scripts.add(resource);
+ }
+
+ return;
+}
+
+function preloadAsStylePropsFromProps(href, props) {
+ return {
+ rel: 'preload',
+ as: 'style',
+ href: href,
+ crossOrigin: props.crossOrigin,
+ fetchPriority: props.fetchPriority,
+ integrity: props.integrity,
+ media: props.media,
+ hrefLang: props.hrefLang,
+ referrerPolicy: props.referrerPolicy
+ };
+}
+
+function stylesheetPropsFromRawProps(rawProps) {
+ return assign({}, rawProps, {
+ 'data-precedence': rawProps.precedence,
+ precedence: null
+ });
+}
+
+function adoptPreloadCredentials(target, preloadState) {
+ if (target.crossOrigin == null) target.crossOrigin = preloadState[0];
+ if (target.integrity == null) target.integrity = preloadState[1];
+}
+
+function getPrefetchDNSAsHeader(href) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ return "<" + escapedHref + ">; rel=dns-prefetch";
+}
+
+function getPreconnectAsHeader(href, crossOrigin) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ let value = "<" + escapedHref + ">; rel=preconnect";
+
+ if (typeof crossOrigin === 'string') {
+ const escapedCrossOrigin = escapeStringForLinkHeaderQuotedParamValueContext(crossOrigin);
+ value += "; crossorigin=\"" + escapedCrossOrigin + "\"";
+ }
+
+ return value;
+}
+
+function getPreloadAsHeader(href, as, params) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ const escapedAs = escapeStringForLinkHeaderQuotedParamValueContext(as);
+ let value = "<" + escapedHref + ">; rel=preload; as=\"" + escapedAs + "\"";
+
+ for (const paramName in params) {
+ if (hasOwnProperty.call(params, paramName)) {
+ const paramValue = params[paramName];
+
+ if (typeof paramValue === 'string') {
+ value += "; " + paramName.toLowerCase() + "=\"" + escapeStringForLinkHeaderQuotedParamValueContext(paramValue) + "\"";
+ }
+ }
+ }
+
+ return value;
+}
+
+function getStylesheetPreloadAsHeader(stylesheet) {
+ const props = stylesheet.props;
+ const preloadOptions = {
+ crossOrigin: props.crossOrigin,
+ integrity: props.integrity,
+ nonce: props.nonce,
+ type: props.type,
+ fetchPriority: props.fetchPriority,
+ referrerPolicy: props.referrerPolicy,
+ media: props.media
+ };
+ return getPreloadAsHeader(props.href, 'style', preloadOptions);
+} // This escaping function is only safe to use for href values being written into
+// a "Link" header in between `<` and `>` characters. The primary concern with the href is
+// to escape the bounding characters as well as new lines. This is unsafe to use in any other
+// context
+
+
+const regexForHrefInLinkHeaderURLContext = /[<>\r\n]/g;
+
+function escapeHrefForLinkHeaderURLContext(hrefInput) {
+
+ const coercedHref = '' + hrefInput;
+ return coercedHref.replace(regexForHrefInLinkHeaderURLContext, escapeHrefForLinkHeaderURLContextReplacer);
+}
+
+function escapeHrefForLinkHeaderURLContextReplacer(match) {
+ switch (match) {
+ case '<':
+ return '%3C';
+
+ case '>':
+ return '%3E';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+} // This escaping function is only safe to use for quoted param values in an HTTP header.
+// It is unsafe to use for any value not inside quote marks in parater value position.
+
+
+const regexForLinkHeaderQuotedParamValueContext = /["';,\r\n]/g;
+
+function escapeStringForLinkHeaderQuotedParamValueContext(value, name) {
+
+ const coerced = '' + value;
+ return coerced.replace(regexForLinkHeaderQuotedParamValueContext, escapeStringForLinkHeaderQuotedParamValueContextReplacer);
+}
+
+function escapeStringForLinkHeaderQuotedParamValueContextReplacer(match) {
+ switch (match) {
+ case '"':
+ return '%22';
+
+ case "'":
+ return '%27';
+
+ case ';':
+ return '%3B';
+
+ case ',':
+ return '%2C';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+}
+
+function hoistStyleQueueDependency(styleQueue) {
+ this.styles.add(styleQueue);
+}
+
+function hoistStylesheetDependency(stylesheet) {
+ this.stylesheets.add(stylesheet);
+}
+
+function hoistResources(renderState, source) {
+ const currentBoundaryResources = renderState.boundaryResources;
+
+ if (currentBoundaryResources) {
+ source.styles.forEach(hoistStyleQueueDependency, currentBoundaryResources);
+ source.stylesheets.forEach(hoistStylesheetDependency, currentBoundaryResources);
+ }
+} // This function is called at various times depending on whether we are rendering
+// or prerendering. In this implementation we only actually emit headers once and
+// subsequent calls are ignored. We track whether the request has a completed shell
+// to determine whether we will follow headers with a flush including stylesheets.
+// In the context of prerrender we don't have a completed shell when the request finishes
+// with a postpone in the shell. In the context of a render we don't have a completed shell
+// if this is called before the shell finishes rendering which usually will happen anytime
+// anything suspends in the shell.
+
+function emitEarlyPreloads(renderState, resumableState, shellComplete) {
+ const onHeaders = renderState.onHeaders;
+
+ if (onHeaders) {
+ const headers = renderState.headers;
+
+ if (headers) {
+ let linkHeader = headers.preconnects;
+
+ if (headers.fontPreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.fontPreloads;
+ }
+
+ if (headers.highImagePreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.highImagePreloads;
+ }
+
+ if (!shellComplete) {
+ // We use raw iterators because we want to be able to halt iteration
+ // We could refactor renderState to store these dually in arrays to
+ // make this more efficient at the cost of additional memory and
+ // write overhead. However this code only runs once per request so
+ // for now I consider this sufficient.
+ const queueIter = renderState.styles.values();
+
+ outer: for (let queueStep = queueIter.next(); headers.remainingCapacity > 0 && !queueStep.done; queueStep = queueIter.next()) {
+ const sheets = queueStep.value.sheets;
+ const sheetIter = sheets.values();
+
+ for (let sheetStep = sheetIter.next(); headers.remainingCapacity > 0 && !sheetStep.done; sheetStep = sheetIter.next()) {
+ const sheet = sheetStep.value;
+ const props = sheet.props;
+ const key = getResourceKey(props.href);
+ const header = getStylesheetPreloadAsHeader(sheet); // We mutate the capacity b/c we don't want to keep checking if later headers will fit.
+ // This means that a particularly long header might close out the header queue where later
+ // headers could still fit. We could in the future alter the behavior here based on prerender vs render
+ // since during prerender we aren't as concerned with pure runtime performance.
+
+ if ((headers.remainingCapacity -= header.length) >= 2) {
+ renderState.resets.style[key] = PRELOAD_NO_CREDS;
+
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += header; // We already track that the resource exists in resumableState however
+ // if the resumableState resets because we postponed in the shell
+ // which is what is happening in this branch if we are prerendering
+ // then we will end up resetting the resumableState. When it resets we
+ // want to record the fact that this stylesheet was already preloaded
+
+ renderState.resets.style[key] = typeof props.crossOrigin === 'string' || typeof props.integrity === 'string' ? [props.crossOrigin, props.integrity] : PRELOAD_NO_CREDS;
+ } else {
+ break outer;
+ }
+ }
+ }
+ }
+
+ if (linkHeader) {
+ onHeaders({
+ Link: linkHeader
+ });
+ } else {
+ // We still call this with no headers because a user may be using it as a signal that
+ // it React will not provide any headers
+ onHeaders({});
+ }
+
+ renderState.headers = null;
+ return;
+ }
+ }
+}
+const NotPendingTransition = NotPending;
+
+// ATTENTION
+// When adding new symbols to this file,
+// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
+// The Symbol used to tag the ReactElement-like types.
+const REACT_ELEMENT_TYPE = Symbol.for('react.element');
+const REACT_PORTAL_TYPE = Symbol.for('react.portal');
+const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
+const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
+const REACT_PROFILER_TYPE = Symbol.for('react.profiler');
+const REACT_PROVIDER_TYPE = Symbol.for('react.provider');
+const REACT_CONTEXT_TYPE = Symbol.for('react.context');
+const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
+const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
+const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
+const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
+const REACT_MEMO_TYPE = Symbol.for('react.memo');
+const REACT_LAZY_TYPE = Symbol.for('react.lazy');
+const REACT_SCOPE_TYPE = Symbol.for('react.scope');
+const REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');
+const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
+const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');
+const REACT_CACHE_TYPE = Symbol.for('react.cache');
+const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value');
+const REACT_MEMO_CACHE_SENTINEL = Symbol.for('react.memo_cache_sentinel');
+const REACT_POSTPONE_TYPE = Symbol.for('react.postpone');
+const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
+const FAUX_ITERATOR_SYMBOL = '@@iterator';
+function getIteratorFn(maybeIterable) {
+ if (maybeIterable === null || typeof maybeIterable !== 'object') {
+ return null;
+ }
+
+ const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
+
+ if (typeof maybeIterator === 'function') {
+ return maybeIterator;
+ }
+
+ return null;
+}
+
+function getWrappedName(outerType, innerType, wrapperName) {
+ const displayName = outerType.displayName;
+
+ if (displayName) {
+ return displayName;
+ }
+
+ const functionName = innerType.displayName || innerType.name || '';
+ return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName;
+} // Keep in sync with react-reconciler/getComponentNameFromFiber
+
+
+function getContextName(type) {
+ return type.displayName || 'Context';
+} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+
+
+function getComponentNameFromType(type) {
+ if (type == null) {
+ // Host root, text node or just invalid type.
+ return null;
+ }
+
+ if (typeof type === 'function') {
+ return type.displayName || type.name || null;
+ }
+
+ if (typeof type === 'string') {
+ return type;
+ }
+
+ switch (type) {
+ case REACT_FRAGMENT_TYPE:
+ return 'Fragment';
+
+ case REACT_PORTAL_TYPE:
+ return 'Portal';
+
+ case REACT_PROFILER_TYPE:
+ return 'Profiler';
+
+ case REACT_STRICT_MODE_TYPE:
+ return 'StrictMode';
+
+ case REACT_SUSPENSE_TYPE:
+ return 'Suspense';
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ return 'SuspenseList';
+
+ case REACT_CACHE_TYPE:
+ {
+ return 'Cache';
+ }
+
+ }
+
+ if (typeof type === 'object') {
+ switch (type.$$typeof) {
+ case REACT_CONTEXT_TYPE:
+ const context = type;
+ return getContextName(context) + '.Consumer';
+
+ case REACT_PROVIDER_TYPE:
+ const provider = type;
+ return getContextName(provider._context) + '.Provider';
+
+ case REACT_FORWARD_REF_TYPE:
+ return getWrappedName(type, type.render, 'ForwardRef');
+
+ case REACT_MEMO_TYPE:
+ const outerName = type.displayName || null;
+
+ if (outerName !== null) {
+ return outerName;
+ }
+
+ return getComponentNameFromType(type.type) || 'Memo';
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyComponent = type;
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+
+ try {
+ return getComponentNameFromType(init(payload));
+ } catch (x) {
+ return null;
+ }
+ }
+
+ case REACT_SERVER_CONTEXT_TYPE:
+ {
+ const context2 = type;
+ return (context2.displayName || context2._globalName) + '.Provider';
+ }
+
+ }
+ }
+
+ return null;
+}
+
+const emptyContextObject = {};
+
+function getMaskedContext(type, unmaskedContext) {
+ {
+ const contextTypes = type.contextTypes;
+
+ if (!contextTypes) {
+ return emptyContextObject;
+ }
+
+ const context = {};
+
+ for (const key in contextTypes) {
+ context[key] = unmaskedContext[key];
+ }
+
+ return context;
+ }
+}
+function processChildContext(instance, type, parentContext, childContextTypes) {
+ {
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
+ if (typeof instance.getChildContext !== 'function') {
+
+ return parentContext;
+ }
+
+ const childContext = instance.getChildContext();
+
+ for (const contextKey in childContext) {
+ if (!(contextKey in childContextTypes)) {
+ throw Error(formatProdErrorMessage(108, getComponentNameFromType(type) || 'Unknown', contextKey));
+ }
+ }
+
+ return assign({}, parentContext, childContext);
+ }
+}
+
+// Forming a reverse tree.
+// The structure of a context snapshot is an implementation of this file.
+// Currently, it's implemented as tracking the current active node.
+
+
+const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
+// This global (actually thread local) state represents what state all those "current",
+// fields are currently in.
+
+let currentActiveSnapshot = null;
+
+function popNode(prev) {
+ {
+ prev.context._currentValue = prev.parentValue;
+ }
+}
+
+function pushNode(next) {
+ {
+ next.context._currentValue = next.value;
+ }
+}
+
+function popToNearestCommonAncestor(prev, next) {
+ if (prev === next) ; else {
+ popNode(prev);
+ const parentPrev = prev.parent;
+ const parentNext = next.parent;
+
+ if (parentPrev === null) {
+ if (parentNext !== null) {
+ throw Error(formatProdErrorMessage(401));
+ }
+ } else {
+ if (parentNext === null) {
+ throw Error(formatProdErrorMessage(401));
+ }
+
+ popToNearestCommonAncestor(parentPrev, parentNext);
+ } // On the way back, we push the new ones that weren't common.
+
+
+ pushNode(next);
+ }
+}
+
+function popAllPrevious(prev) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev !== null) {
+ popAllPrevious(parentPrev);
+ }
+}
+
+function pushAllNext(next) {
+ const parentNext = next.parent;
+
+ if (parentNext !== null) {
+ pushAllNext(parentNext);
+ }
+
+ pushNode(next);
+}
+
+function popPreviousToCommonLevel(prev, next) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev === null) {
+ throw Error(formatProdErrorMessage(402));
+ }
+
+ if (parentPrev.depth === next.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(parentPrev, next);
+ } else {
+ // We must still be deeper.
+ popPreviousToCommonLevel(parentPrev, next);
+ }
+}
+
+function popNextToCommonLevel(prev, next) {
+ const parentNext = next.parent;
+
+ if (parentNext === null) {
+ throw Error(formatProdErrorMessage(402));
+ }
+
+ if (prev.depth === parentNext.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(prev, parentNext);
+ } else {
+ // We must still be deeper.
+ popNextToCommonLevel(prev, parentNext);
+ }
+
+ pushNode(next);
+} // Perform context switching to the new snapshot.
+// To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
+// updating all the context's current values. That way reads, always just read the current value.
+// At the cost of updating contexts even if they're never read by this subtree.
+
+
+function switchContext(newSnapshot) {
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
+ // We also need to update any new contexts that are now on the stack with the deepest value.
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
+ // for that. Therefore this algorithm is recursive.
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
+ // 3) Then we reapply new contexts on the way back up the stack.
+ const prev = currentActiveSnapshot;
+ const next = newSnapshot;
+
+ if (prev !== next) {
+ if (prev === null) {
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
+ pushAllNext(next);
+ } else if (next === null) {
+ popAllPrevious(prev);
+ } else if (prev.depth === next.depth) {
+ popToNearestCommonAncestor(prev, next);
+ } else if (prev.depth > next.depth) {
+ popPreviousToCommonLevel(prev, next);
+ } else {
+ popNextToCommonLevel(prev, next);
+ }
+
+ currentActiveSnapshot = next;
+ }
+}
+function pushProvider(context, nextValue) {
+ let prevValue;
+
+ {
+ prevValue = context._currentValue;
+ context._currentValue = nextValue;
+ }
+
+ const prevNode = currentActiveSnapshot;
+ const newNode = {
+ parent: prevNode,
+ depth: prevNode === null ? 0 : prevNode.depth + 1,
+ context: context,
+ parentValue: prevValue,
+ value: nextValue
+ };
+ currentActiveSnapshot = newNode;
+ return newNode;
+}
+function popProvider(context) {
+ const prevSnapshot = currentActiveSnapshot;
+
+ if (prevSnapshot === null) {
+ throw Error(formatProdErrorMessage(403));
+ }
+
+ {
+ const value = prevSnapshot.parentValue;
+
+ if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) {
+ prevSnapshot.context._currentValue = prevSnapshot.context._defaultValue;
+ } else {
+ prevSnapshot.context._currentValue = value;
+ }
+ }
+
+ return currentActiveSnapshot = prevSnapshot.parent;
+}
+function getActiveContext() {
+ return currentActiveSnapshot;
+}
+function readContext$1(context) {
+ const value = context._currentValue ;
+ return value;
+}
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ *
+ * Note that this module is currently shared and assumed to be stateless.
+ * If this becomes an actual Map, that will break.
+ */
+function get(key) {
+ return key._reactInternals;
+}
+function set(key, value) {
+ key._reactInternals = value;
+}
+
+const classComponentUpdater = {
+ isMounted(inst) {
+ return false;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueSetState(inst, payload, callback) {
+ const internals = get(inst);
+
+ if (internals.queue === null) ; else {
+ internals.queue.push(payload);
+ }
+ },
+
+ enqueueReplaceState(inst, payload, callback) {
+ const internals = get(inst);
+ internals.replace = true;
+ internals.queue = [payload];
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueForceUpdate(inst, callback) {
+ }
+
+};
+
+function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) {
+ const partialState = getDerivedStateFromProps(nextProps, prevState);
+
+
+ const newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);
+ return newState;
+}
+
+function constructClassInstance(ctor, props, maskedLegacyContext) {
+ let context = emptyContextObject;
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ context = readContext$1(contextType);
+ } else {
+ context = maskedLegacyContext;
+ }
+
+ const instance = new ctor(props, context);
+
+ return instance;
+}
+
+function callComponentWillMount(type, instance) {
+ const oldState = instance.state;
+
+ if (typeof instance.componentWillMount === 'function') {
+
+ instance.componentWillMount();
+ }
+
+ if (typeof instance.UNSAFE_componentWillMount === 'function') {
+ instance.UNSAFE_componentWillMount();
+ }
+
+ if (oldState !== instance.state) {
+
+ classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
+ }
+}
+
+function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) {
+ if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
+ const oldQueue = internalInstance.queue;
+ const oldReplace = internalInstance.replace;
+ internalInstance.queue = null;
+ internalInstance.replace = false;
+
+ if (oldReplace && oldQueue.length === 1) {
+ inst.state = oldQueue[0];
+ } else {
+ let nextState = oldReplace ? oldQueue[0] : inst.state;
+ let dontMutate = true;
+
+ for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
+ const partial = oldQueue[i];
+ const partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial;
+
+ if (partialState != null) {
+ if (dontMutate) {
+ dontMutate = false;
+ nextState = assign({}, nextState, partialState);
+ } else {
+ assign(nextState, partialState);
+ }
+ }
+ }
+
+ inst.state = nextState;
+ }
+ } else {
+ internalInstance.queue = null;
+ }
+} // Invokes the mount life-cycles on a previously never rendered instance.
+
+
+function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) {
+
+ const initialState = instance.state !== undefined ? instance.state : null;
+ instance.updater = classComponentUpdater;
+ instance.props = newProps;
+ instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway.
+ // The internal instance will be used to manage updates that happen during this mount.
+
+ const internalInstance = {
+ queue: [],
+ replace: false
+ };
+ set(instance, internalInstance);
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ instance.context = readContext$1(contextType);
+ } else {
+ instance.context = maskedLegacyContext;
+ }
+
+ const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
+
+ if (typeof getDerivedStateFromProps === 'function') {
+ instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps);
+ } // In order to support react-lifecycles-compat polyfilled components,
+ // Unsafe lifecycles should not be invoked for components using the new APIs.
+
+
+ if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
+ callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's
+ // process them now.
+
+ processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext);
+ }
+}
+
+// Ids are base 32 strings whose binary representation corresponds to the
+// position of a node in a tree.
+// Every time the tree forks into multiple children, we add additional bits to
+// the left of the sequence that represent the position of the child within the
+// current level of children.
+//
+// 00101 00010001011010101
+// ╰─┬─╯ ╰───────┬───────╯
+// Fork 5 of 20 Parent id
+//
+// The leading 0s are important. In the above example, you only need 3 bits to
+// represent slot 5. However, you need 5 bits to represent all the forks at
+// the current level, so we must account for the empty bits at the end.
+//
+// For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise,
+// the zeroth id at a level would be indistinguishable from its parent.
+//
+// If a node has only one child, and does not materialize an id (i.e. does not
+// contain a useId hook), then we don't need to allocate any space in the
+// sequence. It's treated as a transparent indirection. For example, these two
+// trees produce the same ids:
+//
+// <> <>
+//
+//
+// >
+//
+// >
+//
+// However, we cannot skip any node that materializes an id. Otherwise, a parent
+// id that does not fork would be indistinguishable from its child id. For
+// example, this tree does not fork, but the parent and child must have
+// different ids.
+//
+//
+//
+//
+//
+// To handle this scenario, every time we materialize an id, we allocate a
+// new level with a single slot. You can think of this as a fork with only one
+// prong, or an array of children with length 1.
+//
+// It's possible for the size of the sequence to exceed 32 bits, the max
+// size for bitwise operations. When this happens, we make more room by
+// converting the right part of the id to a string and storing it in an overflow
+// variable. We use a base 32 string representation, because 32 is the largest
+// power of 2 that is supported by toString(). We want the base to be large so
+// that the resulting ids are compact, and we want the base to be a power of 2
+// because every log2(base) bits corresponds to a single character, i.e. every
+// log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without
+// affecting the final result.
+const emptyTreeContext = {
+ id: 1,
+ overflow: ''
+};
+function getTreeId(context) {
+ const overflow = context.overflow;
+ const idWithLeadingBit = context.id;
+ const id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);
+ return id.toString(32) + overflow;
+}
+function pushTreeContext(baseContext, totalChildren, index) {
+ const baseIdWithLeadingBit = baseContext.id;
+ const baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part
+ // of the id; we use it to account for leading 0s.
+
+ const baseLength = getBitLength(baseIdWithLeadingBit) - 1;
+ const baseId = baseIdWithLeadingBit & ~(1 << baseLength);
+ const slot = index + 1;
+ const length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into
+ // consideration the leading 1 we use to mark the end of the sequence.
+
+ if (length > 30) {
+ // We overflowed the bitwise-safe range. Fall back to slower algorithm.
+ // This branch assumes the length of the base id is greater than 5; it won't
+ // work for smaller ids, because you need 5 bits per character.
+ //
+ // We encode the id in multiple steps: first the base id, then the
+ // remaining digits.
+ //
+ // Each 5 bit sequence corresponds to a single base 32 character. So for
+ // example, if the current id is 23 bits long, we can convert 20 of those
+ // bits into a string of 4 characters, with 3 bits left over.
+ //
+ // First calculate how many bits in the base id represent a complete
+ // sequence of characters.
+ const numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.
+
+ const newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.
+
+ const newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.
+
+ const restOfBaseId = baseId >> numberOfOverflowBits;
+ const restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because
+ // we made more room, this time it won't overflow.
+
+ const restOfLength = getBitLength(totalChildren) + restOfBaseLength;
+ const restOfNewBits = slot << restOfBaseLength;
+ const id = restOfNewBits | restOfBaseId;
+ const overflow = newOverflow + baseOverflow;
+ return {
+ id: 1 << restOfLength | id,
+ overflow
+ };
+ } else {
+ // Normal path
+ const newBits = slot << baseLength;
+ const id = newBits | baseId;
+ const overflow = baseOverflow;
+ return {
+ id: 1 << length | id,
+ overflow
+ };
+ }
+}
+
+function getBitLength(number) {
+ return 32 - clz32(number);
+}
+
+function getLeadingBit(id) {
+ return 1 << getBitLength(id) - 1;
+} // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback.
+
+
+const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.
+// Based on:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+const log = Math.log;
+const LN2 = Math.LN2;
+
+function clz32Fallback(x) {
+ const asUint = x >>> 0;
+
+ if (asUint === 0) {
+ return 32;
+ }
+
+ return 31 - (log(asUint) / LN2 | 0) | 0;
+}
+
+// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
+// changes to one module should be reflected in the others.
+// TODO: Rename this module and the corresponding Fiber one to "Thenable"
+// instead of "Wakeable". Or some other more appropriate name.
+// An error that is thrown (e.g. by `use`) to trigger Suspense. If we
+// detect this is caught by userspace, we'll log a warning in development.
+const SuspenseException = Error(formatProdErrorMessage(460));
+function createThenableState() {
+ // The ThenableState is created the first time a component suspends. If it
+ // suspends again, we'll reuse the same state.
+ return [];
+}
+
+function noop$2() {}
+
+function trackUsedThenable(thenableState, thenable, index) {
+ const previous = thenableState[index];
+
+ if (previous === undefined) {
+ thenableState.push(thenable);
+ } else {
+ if (previous !== thenable) {
+ // Reuse the previous thenable, and drop the new one. We can assume
+ // they represent the same value, because components are idempotent.
+ // Avoid an unhandled rejection errors for the Promises that we'll
+ // intentionally ignore.
+ thenable.then(noop$2, noop$2);
+ thenable = previous;
+ }
+ } // We use an expando to track the status and result of a thenable so that we
+ // can synchronously unwrap the value. Think of this as an extension of the
+ // Promise API, or a custom interface that is a superset of Thenable.
+ //
+ // If the thenable doesn't have a status, set it to "pending" and attach
+ // a listener that will update its status and result when it resolves.
+
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledValue = thenable.value;
+ return fulfilledValue;
+ }
+
+ case 'rejected':
+ {
+ const rejectedError = thenable.reason;
+ throw rejectedError;
+ }
+
+ default:
+ {
+ if (typeof thenable.status === 'string') ; else {
+ const pendingThenable = thenable;
+ pendingThenable.status = 'pending';
+ pendingThenable.then(fulfilledValue => {
+ if (thenable.status === 'pending') {
+ const fulfilledThenable = thenable;
+ fulfilledThenable.status = 'fulfilled';
+ fulfilledThenable.value = fulfilledValue;
+ }
+ }, error => {
+ if (thenable.status === 'pending') {
+ const rejectedThenable = thenable;
+ rejectedThenable.status = 'rejected';
+ rejectedThenable.reason = error;
+ }
+ }); // Check one more time in case the thenable resolved synchronously
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledThenable = thenable;
+ return fulfilledThenable.value;
+ }
+
+ case 'rejected':
+ {
+ const rejectedThenable = thenable;
+ throw rejectedThenable.reason;
+ }
+ }
+ } // Suspend.
+ //
+ // Throwing here is an implementation detail that allows us to unwind the
+ // call stack. But we shouldn't allow it to leak into userspace. Throw an
+ // opaque placeholder value instead of the actual thenable. If it doesn't
+ // get captured by the work loop, log a warning, because that means
+ // something in userspace must have caught it.
+
+
+ suspendedThenable = thenable;
+ throw SuspenseException;
+ }
+ }
+} // This is used to track the actual thenable that suspended so it can be
+// passed to the rest of the Suspense implementation — which, for historical
+// reasons, expects to receive a thenable.
+
+let suspendedThenable = null;
+function getSuspendedThenable() {
+ // This is called right after `use` suspends by throwing an exception. `use`
+ // throws an opaque value instead of the thenable itself so that it can't be
+ // caught in userspace. Then the work loop accesses the actual thenable using
+ // this function.
+ if (suspendedThenable === null) {
+ throw Error(formatProdErrorMessage(459));
+ }
+
+ const thenable = suspendedThenable;
+ suspendedThenable = null;
+ return thenable;
+}
+
+/**
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+ */
+function is(x, y) {
+ return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
+ ;
+}
+
+const objectIs = // $FlowFixMe[method-unbinding]
+typeof Object.is === 'function' ? Object.is : is;
+
+let currentlyRenderingComponent = null;
+let currentlyRenderingTask = null;
+let currentlyRenderingRequest = null;
+let currentlyRenderingKeyPath = null;
+let firstWorkInProgressHook = null;
+let workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook
+
+let isReRender = false; // Whether an update was scheduled during the currently executing render pass.
+
+let didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component
+
+let localIdCounter = 0; // Chunks that should be pushed to the stream once the component
+// finishes rendering.
+// Counts the number of useFormState calls in this component
+
+let formStateCounter = 0; // The index of the useFormState hook that matches the one passed in at the
+// root during an MPA navigation, if any.
+
+let formStateMatchingIndex = -1; // Counts the number of use(thenable) calls in this component
+
+let thenableIndexCounter = 0;
+let thenableState = null; // Lazily created map of render-phase updates
+
+let renderPhaseUpdates = null; // Counter to prevent infinite loops.
+
+let numberOfReRenders = 0;
+const RE_RENDER_LIMIT = 25;
+
+function resolveCurrentlyRenderingComponent() {
+ if (currentlyRenderingComponent === null) {
+ throw Error(formatProdErrorMessage(321));
+ }
+
+ return currentlyRenderingComponent;
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+
+ return false;
+ }
+
+
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ if (objectIs(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+function createHook() {
+ if (numberOfReRenders > 0) {
+ throw Error(formatProdErrorMessage(312));
+ }
+
+ return {
+ memoizedState: null,
+ queue: null,
+ next: null
+ };
+}
+
+function createWorkInProgressHook() {
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ if (firstWorkInProgressHook === null) {
+ isReRender = false;
+ firstWorkInProgressHook = workInProgressHook = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = firstWorkInProgressHook;
+ }
+ } else {
+ if (workInProgressHook.next === null) {
+ isReRender = false; // Append to the end of the list
+
+ workInProgressHook = workInProgressHook.next = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = workInProgressHook.next;
+ }
+ }
+
+ return workInProgressHook;
+}
+
+function prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState) {
+ currentlyRenderingComponent = componentIdentity;
+ currentlyRenderingTask = task;
+ currentlyRenderingRequest = request;
+ currentlyRenderingKeyPath = keyPath;
+ // didScheduleRenderPhaseUpdate = false;
+ // firstWorkInProgressHook = null;
+ // numberOfReRenders = 0;
+ // renderPhaseUpdates = null;
+ // workInProgressHook = null;
+
+
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ thenableState = prevThenableState;
+}
+function finishHooks(Component, props, children, refOrContext) {
+ // This must be called after every function component to prevent hooks from
+ // being used in classes.
+ while (didScheduleRenderPhaseUpdate) {
+ // Updates were scheduled during the render phase. They are stored in
+ // the `renderPhaseUpdates` map. Call the component again, reusing the
+ // work-in-progress hooks and applying the additional updates on top. Keep
+ // restarting until no more updates are scheduled.
+ didScheduleRenderPhaseUpdate = false;
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ numberOfReRenders += 1; // Start over from the beginning of the list
+
+ workInProgressHook = null;
+ children = Component(props, refOrContext);
+ }
+
+ resetHooksState();
+ return children;
+}
+function getThenableStateAfterSuspending() {
+ const state = thenableState;
+ thenableState = null;
+ return state;
+}
+function checkDidRenderIdHook() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ const didRenderIdHook = localIdCounter !== 0;
+ return didRenderIdHook;
+}
+function getFormStateCount() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateCounter;
+}
+function getFormStateMatchingIndex() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateMatchingIndex;
+} // Reset the internal hooks state if an error occurs while rendering a component
+
+function resetHooksState() {
+
+ currentlyRenderingComponent = null;
+ currentlyRenderingTask = null;
+ currentlyRenderingRequest = null;
+ currentlyRenderingKeyPath = null;
+ didScheduleRenderPhaseUpdate = false;
+ firstWorkInProgressHook = null;
+ numberOfReRenders = 0;
+ renderPhaseUpdates = null;
+ workInProgressHook = null;
+}
+
+function readContext(context) {
+
+ return readContext$1(context);
+}
+
+function useContext(context) {
+
+ resolveCurrentlyRenderingComponent();
+ return readContext$1(context);
+}
+
+function basicStateReducer(state, action) {
+ // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
+ return typeof action === 'function' ? action(state) : action;
+}
+
+function useState(initialState) {
+
+ return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers
+ initialState);
+}
+function useReducer(reducer, initialArg, init) {
+
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+
+ if (isReRender) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ // current hook.
+ const queue = workInProgressHook.queue;
+ const dispatch = queue.dispatch;
+
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate !== undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.delete(queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ let newState = workInProgressHook.memoizedState;
+ let update = firstRenderPhaseUpdate;
+
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ const action = update.action;
+
+ newState = reducer(newState, action);
+
+
+ update = update.next;
+ } while (update !== null); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ workInProgressHook.memoizedState = newState;
+ return [newState, dispatch];
+ }
+ } // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ return [workInProgressHook.memoizedState, dispatch];
+ } else {
+
+ let initialState;
+
+ if (reducer === basicStateReducer) {
+ // Special case for `useState`.
+ initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
+ } else {
+ initialState = init !== undefined ? init(initialArg) : initialArg;
+ }
+
+
+ workInProgressHook.memoizedState = initialState; // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ const queue = workInProgressHook.queue = {
+ last: null,
+ dispatch: null
+ };
+ const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ return [workInProgressHook.memoizedState, dispatch];
+ }
+}
+
+function useMemo(nextCreate, deps) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const nextDeps = deps === undefined ? null : deps;
+
+ if (workInProgressHook !== null) {
+ const prevState = workInProgressHook.memoizedState;
+
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ const prevDeps = prevState[1];
+
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ }
+
+ const nextValue = nextCreate();
+
+
+ workInProgressHook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function useRef(initialValue) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const previousRef = workInProgressHook.memoizedState;
+
+ if (previousRef === null) {
+ const ref = {
+ current: initialValue
+ };
+
+
+ workInProgressHook.memoizedState = ref;
+ return ref;
+ } else {
+ return previousRef;
+ }
+}
+
+function dispatchAction(componentIdentity, queue, action) {
+ if (numberOfReRenders >= RE_RENDER_LIMIT) {
+ throw Error(formatProdErrorMessage(301));
+ }
+
+ if (componentIdentity === currentlyRenderingComponent) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ const update = {
+ action,
+ next: null
+ };
+
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate === undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+
+ lastRenderPhaseUpdate.next = update;
+ }
+ }
+}
+
+function useCallback(callback, deps) {
+ return useMemo(() => callback, deps);
+}
+
+function throwOnUseEffectEventCall() {
+ throw Error(formatProdErrorMessage(440));
+}
+
+function useEffectEvent(callback) {
+ // $FlowIgnore[incompatible-return]
+ return throwOnUseEffectEventCall;
+}
+
+function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
+ if (getServerSnapshot === undefined) {
+ throw Error(formatProdErrorMessage(407));
+ }
+
+ return getServerSnapshot();
+}
+
+function useDeferredValue(value, initialValue) {
+ resolveCurrentlyRenderingComponent();
+
+ {
+ return initialValue !== undefined ? initialValue : value;
+ }
+}
+
+function unsupportedStartTransition() {
+ throw Error(formatProdErrorMessage(394));
+}
+
+function useTransition() {
+ resolveCurrentlyRenderingComponent();
+ return [false, unsupportedStartTransition];
+}
+
+function useHostTransitionStatus() {
+ resolveCurrentlyRenderingComponent();
+ return NotPendingTransition;
+}
+
+function unsupportedSetOptimisticState() {
+ throw Error(formatProdErrorMessage(479));
+}
+
+function useOptimistic(passthrough, reducer) {
+ resolveCurrentlyRenderingComponent();
+ return [passthrough, unsupportedSetOptimisticState];
+}
+
+function createPostbackFormStateKey(permalink, componentKeyPath, hookIndex) {
+ if (permalink !== undefined) {
+ // Don't bother to hash a permalink-based key since it's already short.
+ return 'p' + permalink;
+ } else {
+ // Append a node to the key path that represents the form state hook.
+ const keyPath = [componentKeyPath, null, hookIndex]; // Key paths are hashed to reduce the size. It does not need to be secure,
+ // and it's more important that it's fast than that it's completely
+ // collision-free.
+
+ const keyPathHash = createFastHashJS(JSON.stringify(keyPath));
+ return 'k' + keyPathHash;
+ }
+}
+
+function useFormState(action, initialState, permalink) {
+ resolveCurrentlyRenderingComponent(); // Count the number of useFormState hooks per component. We also use this to
+ // track the position of this useFormState hook relative to the other ones in
+ // this component, so we can generate a unique key for each one.
+
+ const formStateHookIndex = formStateCounter++;
+ const request = currentlyRenderingRequest; // $FlowIgnore[prop-missing]
+
+ const formAction = action.$$FORM_ACTION;
+
+ if (typeof formAction === 'function') {
+ // This is a server action. These have additional features to enable
+ // MPA-style form submissions with progressive enhancement.
+ // TODO: If the same permalink is passed to multiple useFormStates, and
+ // they all have the same action signature, Fizz will pass the postback
+ // state to all of them. We should probably only pass it to the first one,
+ // and/or warn.
+ // The key is lazily generated and deduped so the that the keypath doesn't
+ // get JSON.stringify-ed unnecessarily, and at most once.
+ let nextPostbackStateKey = null; // Determine the current form state. If we received state during an MPA form
+ // submission, then we will reuse that, if the action identity matches.
+ // Otherwise we'll use the initial state argument. We will emit a comment
+ // marker into the stream that indicates whether the state was reused.
+
+ let state = initialState;
+ const componentKeyPath = currentlyRenderingKeyPath;
+ const postbackFormState = getFormState(request); // $FlowIgnore[prop-missing]
+
+ const isSignatureEqual = action.$$IS_SIGNATURE_EQUAL;
+
+ if (postbackFormState !== null && typeof isSignatureEqual === 'function') {
+ const postbackKey = postbackFormState[1];
+ const postbackReferenceId = postbackFormState[2];
+ const postbackBoundArity = postbackFormState[3];
+
+ if (isSignatureEqual.call(action, postbackReferenceId, postbackBoundArity)) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+
+ if (postbackKey === nextPostbackStateKey) {
+ // This was a match
+ formStateMatchingIndex = formStateHookIndex; // Reuse the state that was submitted by the form.
+
+ state = postbackFormState[0];
+ }
+ }
+ } // Bind the state to the first argument of the action.
+
+
+ const boundAction = action.bind(null, state); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ }; // $FlowIgnore[prop-missing]
+
+
+ if (typeof boundAction.$$FORM_ACTION === 'function') {
+ // $FlowIgnore[prop-missing]
+ dispatch.$$FORM_ACTION = prefix => {
+ const metadata = boundAction.$$FORM_ACTION(prefix); // Override the action URL
+
+ if (permalink !== undefined) {
+
+ permalink += '';
+ metadata.action = permalink;
+ }
+
+ const formData = metadata.data;
+
+ if (formData) {
+ if (nextPostbackStateKey === null) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+ }
+
+ formData.append('$ACTION_KEY', nextPostbackStateKey);
+ }
+
+ return metadata;
+ };
+ }
+
+ return [state, dispatch];
+ } else {
+ // This is not a server action, so the implementation is much simpler.
+ // Bind the state to the first argument of the action.
+ const boundAction = action.bind(null, initialState); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ };
+
+ return [initialState, dispatch];
+ }
+}
+
+function useId() {
+ const task = currentlyRenderingTask;
+ const treeId = getTreeId(task.treeContext);
+ const resumableState = currentResumableState;
+
+ if (resumableState === null) {
+ throw Error(formatProdErrorMessage(404));
+ }
+
+ const localId = localIdCounter++;
+ return makeId(resumableState, treeId, localId);
+}
+
+function use(usable) {
+ if (usable !== null && typeof usable === 'object') {
+ // $FlowFixMe[method-unbinding]
+ if (typeof usable.then === 'function') {
+ // This is a thenable.
+ const thenable = usable;
+ return unwrapThenable(thenable);
+ } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = usable;
+ return readContext(context);
+ }
+ } // eslint-disable-next-line react-internal/safe-string-coercion
+
+
+ throw Error(formatProdErrorMessage(438, String(usable)));
+}
+
+function unwrapThenable(thenable) {
+ const index = thenableIndexCounter;
+ thenableIndexCounter += 1;
+
+ if (thenableState === null) {
+ thenableState = createThenableState();
+ }
+
+ return trackUsedThenable(thenableState, thenable, index);
+}
+
+function unsupportedRefresh() {
+ throw Error(formatProdErrorMessage(393));
+}
+
+function useCacheRefresh() {
+ return unsupportedRefresh;
+}
+
+function useMemoCache(size) {
+ const data = new Array(size);
+
+ for (let i = 0; i < size; i++) {
+ data[i] = REACT_MEMO_CACHE_SENTINEL;
+ }
+
+ return data;
+}
+
+function noop$1() {}
+
+const HooksDispatcher = {
+ readContext,
+ use,
+ useContext,
+ useMemo,
+ useReducer,
+ useRef,
+ useState,
+ useInsertionEffect: noop$1,
+ useLayoutEffect: noop$1,
+ useCallback,
+ // useImperativeHandle is not run in the server environment
+ useImperativeHandle: noop$1,
+ // Effects are not run in the server environment.
+ useEffect: noop$1,
+ // Debugging effect
+ useDebugValue: noop$1,
+ useDeferredValue,
+ useTransition,
+ useId,
+ // Subscriptions are not setup in a server environment.
+ useSyncExternalStore
+};
+
+{
+ HooksDispatcher.useCacheRefresh = useCacheRefresh;
+}
+
+{
+ HooksDispatcher.useEffectEvent = useEffectEvent;
+}
+
+{
+ HooksDispatcher.useMemoCache = useMemoCache;
+}
+
+{
+ HooksDispatcher.useHostTransitionStatus = useHostTransitionStatus;
+}
+
+{
+ HooksDispatcher.useOptimistic = useOptimistic;
+ HooksDispatcher.useFormState = useFormState;
+}
+
+let currentResumableState = null;
+function setCurrentResumableState(resumableState) {
+ currentResumableState = resumableState;
+}
+
+function getCacheSignal() {
+ throw Error(formatProdErrorMessage(248));
+}
+
+function getCacheForType(resourceType) {
+ throw Error(formatProdErrorMessage(248));
+}
+
+const DefaultCacheDispatcher = {
+ getCacheSignal,
+ getCacheForType
+};
+
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
+const ReactCurrentCache = ReactSharedInternals.ReactCurrentCache;
+// The name might be minified but we assume that it's going to be the same generated name. Typically
+// because it's just the same compiled output in practice.
+// resume with segmentID at the index
+
+const CLIENT_RENDERED = 4; // if it errors or infinitely suspends
+
+const PENDING = 0;
+const COMPLETED = 1;
+const FLUSHED = 2;
+const ABORTED = 3;
+const ERRORED = 4;
+const POSTPONED = 5;
+const OPEN = 0;
+const CLOSING = 1;
+const CLOSED = 2; // This is a default heuristic for how to split up the HTML content into progressive
+// loading. Our goal is to be able to display additional new content about every 500ms.
+// Faster than that is unnecessary and should be throttled on the client. It also
+// adds unnecessary overhead to do more splits. We don't know if it's a higher or lower
+// end device but higher end suffer less from the overhead than lower end does from
+// not getting small enough pieces. We error on the side of low end.
+// We base this on low end 3G speeds which is about 500kbits per second. We assume
+// that there can be a reasonable drop off from max bandwidth which leaves you with
+// as little as 80%. We can receive half of that each 500ms - at best. In practice,
+// a little bandwidth is lost to processing and contention - e.g. CSS and images that
+// are downloaded along with the main content. So we estimate about half of that to be
+// the lower end throughput. In other words, we expect that you can at least show
+// about 12.5kb of content per 500ms. Not counting starting latency for the first
+// paint.
+// 500 * 1024 / 8 * .8 * 0.5 / 2
+
+const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
+
+function defaultErrorHandler(error) {
+ console['error'](error); // Don't transform to our wrapper
+
+ return null;
+}
+
+function noop() {}
+
+function createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, formState) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState,
+ renderState,
+ rootFormatContext,
+ progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: 0,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: formState === undefined ? null : formState
+ }; // This segment represents the root fallback.
+
+ const rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false); // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+function createPrerenderRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone) {
+ const request = createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, undefined); // Start tracking postponed holes during this render.
+
+ request.trackedPostpones = {
+ workingMap: new Map(),
+ rootNodes: [],
+ rootSlots: null
+ };
+ return request;
+}
+function resumeRequest(children, postponedState, renderState, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState: postponedState.resumableState,
+ renderState,
+ rootFormatContext: postponedState.rootFormatContext,
+ progressiveChunkSize: postponedState.progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: postponedState.nextSegmentId,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: null
+ };
+
+ if (typeof postponedState.replaySlots === 'number') {
+ const resumedId = postponedState.replaySlots; // We have a resume slot at the very root. This is effectively just a full rerender.
+
+ const rootSegment = createPendingSegment(request, 0, null, postponedState.rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false);
+ rootSegment.id = resumedId; // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, postponedState.rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+ }
+
+ const replay = {
+ nodes: postponedState.replayNodes,
+ slots: postponedState.replaySlots,
+ pendingTasks: 0
+ };
+ const rootTask = createReplayTask(request, null, replay, children, -1, null, abortSet, null, postponedState.rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+let currentRequest = null;
+function resolveRequest() {
+ if (currentRequest) return currentRequest;
+
+ return null;
+}
+
+function pingTask(request, task) {
+ const pingedTasks = request.pingedTasks;
+ pingedTasks.push(task);
+
+ if (request.pingedTasks.length === 1) {
+ request.flushScheduled = request.destination !== null;
+ scheduleWork(() => performWork(request));
+ }
+}
+
+function createSuspenseBoundary(request, fallbackAbortableTasks) {
+ return {
+ status: PENDING,
+ rootSegmentID: -1,
+ parentFlushed: false,
+ pendingTasks: 0,
+ completedSegments: [],
+ byteSize: 0,
+ fallbackAbortableTasks,
+ errorDigest: null,
+ resources: createBoundaryResources(),
+ trackedContentKeyPath: null,
+ trackedFallbackNode: null
+ };
+}
+
+function createRenderTask(request, thenableState, node, childIndex, blockedBoundary, blockedSegment, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ const task = {
+ replay: null,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createReplayTask(request, thenableState, replay, node, childIndex, blockedBoundary, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ replay.pendingTasks++;
+ const task = {
+ replay,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment: null,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createPendingSegment(request, index, boundary, parentFormatContext, lastPushedText, textEmbedded) {
+ return {
+ status: PENDING,
+ id: -1,
+ // lazily assigned later
+ index,
+ parentFlushed: false,
+ chunks: [],
+ children: [],
+ parentFormatContext,
+ boundary,
+ lastPushedText,
+ textEmbedded
+ };
+} // DEV-only global reference to the currently executing task
+
+function popComponentStackInDEV(task) {
+} // stash the component stack of an unwinding error until it is processed
+
+function logPostpone(request, reason) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ request.onPostpone(reason);
+}
+
+function logRecoverableError(request, error) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ const errorDigest = request.onError(error);
+
+ if (errorDigest != null && typeof errorDigest !== 'string') {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead");
+ }
+
+ return errorDigest;
+}
+
+function fatalError(request, error) {
+ // This is called outside error handling code such as if the root errors outside
+ // a suspense boundary or if the root suspense boundary's fallback errors.
+ // It's also called if React itself or its host configs errors.
+ const onShellError = request.onShellError;
+ onShellError(error);
+ const onFatalError = request.onFatalError;
+ onFatalError(error);
+
+ if (request.destination !== null) {
+ request.status = CLOSED;
+ closeWithError(request.destination, error);
+ } else {
+ request.status = CLOSING;
+ request.fatalError = error;
+ }
+}
+
+function renderSuspenseBoundary(request, someTask, keyPath, props) {
+ if (someTask.replay !== null) {
+ // If we're replaying through this pass, it means we're replaying through
+ // an already completed Suspense boundary. It's too late to do anything about it
+ // so we can just render through it.
+ const prevKeyPath = someTask.keyPath;
+ someTask.keyPath = keyPath;
+ const content = props.children;
+
+ try {
+ renderNode(request, someTask, content, -1);
+ } finally {
+ someTask.keyPath = prevKeyPath;
+ }
+
+ return;
+ } // $FlowFixMe: Refined.
+
+
+ const task = someTask;
+ const prevKeyPath = task.keyPath;
+ const parentBoundary = task.blockedBoundary;
+ const parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for
+ // the fallback so that we can later replace that segment with the content.
+ // This also lets us split out the main content even if it doesn't suspend,
+ // in case it ends up generating a large subtree of content.
+
+ const fallback = props.fallback;
+ const content = props.children;
+ const fallbackAbortSet = new Set();
+ const newBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+
+ if (request.trackedPostpones !== null) {
+ newBoundary.trackedContentKeyPath = keyPath;
+ }
+
+ const insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback.
+
+ const boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false);
+ parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent
+
+ parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately.
+
+ const contentRootSegment = createPendingSegment(request, 0, null, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is
+ // no parent segment so there's nothing to wait on.
+
+ contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks.
+ // I suspect that there might be some efficiency benefits from not creating the suspended task
+ // and instead just using the stack if possible.
+ // TODO: Call this directly instead of messing with saving and restoring contexts.
+ // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and which segment
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = newBoundary;
+ task.blockedSegment = contentRootSegment;
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, newBoundary.resources);
+ }
+
+ task.keyPath = keyPath;
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+ pushSegmentFinale(contentRootSegment.chunks, request.renderState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded);
+ contentRootSegment.status = COMPLETED;
+ queueCompletedSegment(newBoundary, contentRootSegment);
+
+ if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
+ newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ contentRootSegment.status = ERRORED;
+ newBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ newBoundary.errorDigest = errorDigest;
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.blockedSegment = parentSegment;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]];
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones !== null) {
+ // We create a detached replay node to track any postpones inside the fallback.
+ const fallbackReplayNode = [fallbackKeyPath[1], fallbackKeyPath[2], [], null];
+ trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
+
+ if (newBoundary.status === POSTPONED) {
+ // This must exist now.
+ const boundaryReplayNode = trackedPostpones.workingMap.get(keyPath);
+ boundaryReplayNode[4] = fallbackReplayNode;
+ } else {
+ // We might not inject it into the postponed tree, unless the content actually
+ // postpones too. We need to keep track of it until that happpens.
+ newBoundary.trackedFallbackNode = fallbackReplayNode;
+ }
+ } // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+
+ const suspendedFallbackTask = createRenderTask(request, null, fallback, -1, parentBoundary, boundarySegment, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function replaySuspenseBoundary(request, task, keyPath, props, id, childNodes, childSlots, fallbackNodes, fallbackSlots) {
+ const prevKeyPath = task.keyPath;
+ const previousReplaySet = task.replay;
+ const parentBoundary = task.blockedBoundary;
+ const content = props.children;
+ const fallback = props.fallback;
+ const fallbackAbortSet = new Set();
+ const resumedBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = id; // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and replay node
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = resumedBoundary;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, resumedBoundary.resources);
+ }
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+
+ if (resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING) {
+ resumedBoundary.status = COMPLETED;
+ request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ resumedBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ resumedBoundary.errorDigest = errorDigest;
+
+ task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted.
+
+ request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task.
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.replay = previousReplaySet;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+ const fallbackReplay = {
+ nodes: fallbackNodes,
+ slots: fallbackSlots,
+ pendingTasks: 0
+ };
+ const suspendedFallbackTask = createReplayTask(request, null, fallbackReplay, fallback, -1, parentBoundary, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function renderHostElement(request, task, keyPath, type, props) {
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ const children = props.children; // TODO: Make this a Config for replaying.
+
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ } else {
+ // Render
+ const children = pushStartInstance(segment.chunks, type, props, request.resumableState, request.renderState, task.formatContext, segment.lastPushedText);
+ segment.lastPushedText = false;
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ pushEndInstance(segment.chunks, type, props, request.resumableState, prevContext);
+ segment.lastPushedText = false;
+ }
+}
+
+function shouldConstruct(Component) {
+ return Component.prototype && Component.prototype.isReactComponent;
+}
+
+function renderWithHooks(request, task, keyPath, prevThenableState, Component, props, secondArg) {
+ const componentIdentity = {};
+ prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState);
+ const result = Component(props, secondArg);
+ return finishHooks(Component, props, result, secondArg);
+}
+
+function finishClassComponent(request, task, keyPath, instance, Component, props) {
+ const nextChildren = instance.render();
+
+ {
+ const childContextTypes = Component.childContextTypes;
+
+ if (childContextTypes !== null && childContextTypes !== undefined) {
+ const previousContext = task.legacyContext;
+ const mergedContext = processChildContext(instance, Component, previousContext, childContextTypes);
+ task.legacyContext = mergedContext;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.legacyContext = previousContext;
+ return;
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderClassComponent(request, task, keyPath, Component, props) {
+ const maskedContext = getMaskedContext(Component, task.legacyContext) ;
+ const instance = constructClassInstance(Component, props, maskedContext);
+ mountClassInstance(instance, Component, props, maskedContext);
+ finishClassComponent(request, task, keyPath, instance, Component);
+}
+// components for some reason.
+
+function renderIndeterminateComponent(request, task, keyPath, prevThenableState, Component, props) {
+ let legacyContext;
+
+ {
+ legacyContext = getMaskedContext(Component, task.legacyContext);
+ }
+
+ const value = renderWithHooks(request, task, keyPath, prevThenableState, Component, props, legacyContext);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+
+ if ( // Run these checks in production only if the flag is off.
+ // Eventually we'll delete this branch altogether.
+ typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
+
+ mountClassInstance(value, Component, props, legacyContext);
+ finishClassComponent(request, task, keyPath, value, Component);
+ } else {
+
+ finishFunctionComponent(request, task, keyPath, value, hasId, formStateCount, formStateMatchingIndex);
+ }
+}
+
+function finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex) {
+ let didEmitFormStateMarkers = false;
+
+ if (formStateCount !== 0 && request.formState !== null) {
+ // For each useFormState hook, emit a marker that indicates whether we
+ // rendered using the form state passed at the root. We only emit these
+ // markers if form state is passed at the root.
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ didEmitFormStateMarkers = true;
+ const target = segment.chunks;
+
+ for (let i = 0; i < formStateCount; i++) {
+ if (i === formStateMatchingIndex) {
+ pushFormStateMarkerIsMatching(target);
+ } else {
+ pushFormStateMarkerIsNotMatching(target);
+ }
+ }
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+
+ if (hasId) {
+ // This component materialized an id. We treat this as its own level, with
+ // a single "child" slot.
+ const prevTreeContext = task.treeContext;
+ const totalChildren = 1;
+ const index = 0; // Modify the id context. Because we'll need to reset this if something
+ // suspends or errors, we'll use the non-destructive render path.
+
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
+ renderNode(request, task, children, -1); // Like the other contexts, this does not need to be in a finally block
+ // because renderNode takes care of unwinding the stack.
+
+ task.treeContext = prevTreeContext;
+ } else if (didEmitFormStateMarkers) {
+ // If there were formState hooks, we must use the non-destructive path
+ // because this component is not a pure indirection; we emitted markers
+ // to the stream.
+ renderNode(request, task, children, -1);
+ } else {
+ // We're now successfully past this task, and we haven't modified the
+ // context stack. We don't have to pop back to the previous task every
+ // again, so we can use the destructive recursive form.
+ renderNodeDestructive(request, task, null, children, -1);
+ }
+
+ task.keyPath = prevKeyPath;
+}
+
+function resolveDefaultProps(Component, baseProps) {
+ if (Component && Component.defaultProps) {
+ // Resolve default props. Taken from ReactElement
+ const props = assign({}, baseProps);
+ const defaultProps = Component.defaultProps;
+
+ for (const propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+
+ return props;
+ }
+
+ return baseProps;
+}
+
+function renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref) {
+ const children = renderWithHooks(request, task, keyPath, prevThenableState, type.render, props, ref);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+ finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex);
+}
+
+function renderMemo(request, task, keyPath, prevThenableState, type, props, ref) {
+ const innerType = type.type;
+ const resolvedProps = resolveDefaultProps(innerType, props);
+ renderElement(request, task, keyPath, prevThenableState, innerType, resolvedProps, ref);
+}
+
+function renderContextConsumer(request, task, keyPath, context, props) {
+
+ const render = props.children;
+
+ const newValue = readContext$1(context);
+ const newChildren = render(newValue);
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, newChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderContextProvider(request, task, keyPath, type, props) {
+ const context = type._context;
+ const value = props.value;
+ const children = props.children;
+
+ const prevKeyPath = task.keyPath;
+ task.context = pushProvider(context, value);
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, children, -1);
+ task.context = popProvider();
+ task.keyPath = prevKeyPath;
+}
+
+function renderLazyComponent(request, task, keyPath, prevThenableState, lazyComponent, props, ref) {
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+ const Component = init(payload);
+ const resolvedProps = resolveDefaultProps(Component, props);
+ renderElement(request, task, keyPath, prevThenableState, Component, resolvedProps, ref);
+}
+
+function renderOffscreen(request, task, keyPath, props) {
+ const mode = props.mode;
+
+ if (mode === 'hidden') ; else {
+ // A visible Offscreen boundary is treated exactly like a fragment: a
+ // pure indirection.
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ }
+}
+
+function renderElement(request, task, keyPath, prevThenableState, type, props, ref) {
+ if (typeof type === 'function') {
+ if (shouldConstruct(type)) {
+ renderClassComponent(request, task, keyPath, type, props);
+ return;
+ } else {
+ renderIndeterminateComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+
+ if (typeof type === 'string') {
+ renderHostElement(request, task, keyPath, type, props);
+ return;
+ }
+
+ switch (type) {
+ // LegacyHidden acts the same as a fragment. This only works because we
+ // currently assume that every instance of LegacyHidden is accompanied by a
+ // host component wrapper. In the hidden mode, the host component is given a
+ // `hidden` attribute, which ensures that the initial HTML is not visible.
+ // To support the use of LegacyHidden as a true fragment, without an extra
+ // DOM node, we would have to hide the initial HTML in some other way.
+ // TODO: Delete in LegacyHidden. It's an unstable API only used in the
+ // www build. As a migration step, we could add a special prop to Offscreen
+ // that simulates the old behavior (no hiding, no change to effects).
+ case REACT_LEGACY_HIDDEN_TYPE:
+ case REACT_DEBUG_TRACING_MODE_TYPE:
+ case REACT_STRICT_MODE_TYPE:
+ case REACT_PROFILER_TYPE:
+ case REACT_FRAGMENT_TYPE:
+ {
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_OFFSCREEN_TYPE:
+ {
+ renderOffscreen(request, task, keyPath, props);
+ return;
+ }
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ {
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_SCOPE_TYPE:
+ {
+
+ throw Error(formatProdErrorMessage(343));
+ }
+
+ case REACT_SUSPENSE_TYPE:
+ {
+ {
+ renderSuspenseBoundary(request, task, keyPath, props);
+ }
+
+ return;
+ }
+ }
+
+ if (typeof type === 'object' && type !== null) {
+ switch (type.$$typeof) {
+ case REACT_FORWARD_REF_TYPE:
+ {
+ renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_MEMO_TYPE:
+ {
+ renderMemo(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_PROVIDER_TYPE:
+ {
+ renderContextProvider(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_CONTEXT_TYPE:
+ {
+ renderContextConsumer(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_LAZY_TYPE:
+ {
+ renderLazyComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+ }
+
+ let info = '';
+
+ throw Error(formatProdErrorMessage(130, type == null ? type : typeof type, info));
+}
+
+function resumeNode(request, task, segmentId, node, childIndex) {
+ const prevReplay = task.replay;
+ const blockedBoundary = task.blockedBoundary;
+ const resumedSegment = createPendingSegment(request, 0, null, task.formatContext, false, false);
+ resumedSegment.id = segmentId;
+ resumedSegment.parentFlushed = true;
+
+ try {
+ // Convert the current ReplayTask to a RenderTask.
+ const renderTask = task;
+ renderTask.replay = null;
+ renderTask.blockedSegment = resumedSegment;
+ renderNode(request, task, node, childIndex);
+ resumedSegment.status = COMPLETED;
+
+ if (blockedBoundary === null) {
+ request.completedRootSegment = resumedSegment;
+ } else {
+ queueCompletedSegment(blockedBoundary, resumedSegment);
+
+ if (blockedBoundary.parentFlushed) {
+ request.partialBoundaries.push(blockedBoundary);
+ }
+ }
+ } finally {
+ // Restore to a ReplayTask.
+ task.replay = prevReplay;
+ task.blockedSegment = null;
+ }
+}
+
+function replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, replay) {
+ // We're replaying. Find the path to follow.
+ const replayNodes = replay.nodes;
+
+ for (let i = 0; i < replayNodes.length; i++) {
+ // Flow doesn't support refinement on tuples so we do it manually here.
+ const node = replayNodes[i];
+
+ if (keyOrIndex !== node[1]) {
+ continue;
+ }
+
+ if (node.length === 4) {
+ // Matched a replayable path.
+ // Let's double check that the component name matches as a precaution.
+ if (name !== null && name !== node[0]) {
+ throw Error(formatProdErrorMessage(490, node[0], name));
+ }
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ const currentNode = task.node;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0 // TODO check remaining slots
+ ) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ if (task.node === currentNode) {
+ // This same element suspended so we need to pop the replay we just added.
+ task.replay = replay;
+ }
+
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay;
+ } else {
+ // Let's double check that the component type matches.
+ if (type !== REACT_SUSPENSE_TYPE) {
+ const expectedType = 'Suspense';
+ throw Error(formatProdErrorMessage(490, expectedType, getComponentNameFromType(type) || 'Unknown'));
+ } // Matched a replayable path.
+
+
+ replaySuspenseBoundary(request, task, keyPath, props, node[5], node[2], node[3], node[4] === null ? [] : node[4][2], node[4] === null ? null : node[4][3]);
+ } // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+
+ replayNodes.splice(i, 1);
+ return;
+ } // We didn't find any matching nodes. We assume that this element was already
+ // rendered in the prelude and skip it.
+
+} // $FlowFixMe[missing-local-annot]
+
+function renderNodeDestructive(request, task, // The thenable state reused from the previous attempt, if any. This is almost
+// always null, except when called by retryTask.
+prevThenableState, node, childIndex) {
+ {
+ return renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex);
+ }
+} // This function by it self renders a node and consumes the task by mutating it
+// to update the current execution state.
+
+
+function renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex) {
+ if (task.replay !== null && typeof task.replay.slots === 'number') {
+ // TODO: Figure out a cheaper place than this hot path to do this check.
+ const resumeSegmentID = task.replay.slots;
+ resumeNode(request, task, resumeSegmentID, node, childIndex);
+ return;
+ } // Stash the node we're working on. We'll pick up from this task in case
+ // something suspends.
+
+
+ task.node = node;
+ task.childIndex = childIndex; // Handle object types
+
+ if (typeof node === 'object' && node !== null) {
+ switch (node.$$typeof) {
+ case REACT_ELEMENT_TYPE:
+ {
+ const element = node;
+ const type = element.type;
+ const key = element.key;
+ const props = element.props;
+ const ref = element.ref;
+ const name = getComponentNameFromType(type);
+ const keyOrIndex = key == null ? childIndex === -1 ? 0 : childIndex : key;
+ const keyPath = [task.keyPath, name, keyOrIndex];
+
+ if (task.replay !== null) {
+ replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, task.replay); // No matches found for this node. We assume it's already emitted in the
+ // prelude and skip it during the replay.
+ } else {
+ // We're doing a plain render.
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+ }
+
+ return;
+ }
+
+ case REACT_PORTAL_TYPE:
+ throw Error(formatProdErrorMessage(257));
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyNode = node;
+ const payload = lazyNode._payload;
+ const init = lazyNode._init;
+ let resolvedNode;
+
+ {
+ resolvedNode = init(payload);
+ }
+
+ renderNodeDestructive(request, task, null, resolvedNode, childIndex);
+ return;
+ }
+ }
+
+ if (isArray(node)) {
+ renderChildrenArray(request, task, node, childIndex);
+ return;
+ }
+
+ const iteratorFn = getIteratorFn(node);
+
+ if (iteratorFn) {
+
+ const iterator = iteratorFn.call(node);
+
+ if (iterator) {
+ // We need to know how many total children are in this set, so that we
+ // can allocate enough id slots to acommodate them. So we must exhaust
+ // the iterator before we start recursively rendering the children.
+ // TODO: This is not great but I think it's inherent to the id
+ // generation algorithm.
+ let step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that.
+
+ if (!step.done) {
+ const children = [];
+
+ do {
+ children.push(step.value);
+ step = iterator.next();
+ } while (!step.done);
+
+ renderChildrenArray(request, task, children, childIndex);
+ return;
+ }
+
+ return;
+ }
+ } // Usables are a valid React node type. When React encounters a Usable in
+ // a child position, it unwraps it using the same algorithm as `use`. For
+ // example, for promises, React will throw an exception to unwind the
+ // stack, then replay the component once the promise resolves.
+ //
+ // A difference from `use` is that React will keep unwrapping the value
+ // until it reaches a non-Usable type.
+ //
+ // e.g. Usable>> should resolve to T
+
+
+ const maybeUsable = node;
+
+ if (typeof maybeUsable.then === 'function') {
+ const thenable = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable), childIndex);
+ }
+
+ if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, readContext$1(context), childIndex);
+ } // $FlowFixMe[method-unbinding]
+
+
+ const childString = Object.prototype.toString.call(node);
+ throw Error(formatProdErrorMessage(31, childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString));
+ }
+
+ if (typeof node === 'string') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+
+ if (typeof node === 'number') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, '' + node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+}
+
+function replayFragment(request, task, children, childIndex) {
+ // If we're supposed follow this array, we'd expect to see a ReplayNode matching
+ // this fragment.
+ const replay = task.replay;
+ const replayNodes = replay.nodes;
+
+ for (let j = 0; j < replayNodes.length; j++) {
+ const node = replayNodes[j];
+
+ if (node[1] !== childIndex) {
+ continue;
+ } // Matched a replayable path.
+
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderChildrenArray(request, task, children, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+ // This is an error, stash the component stack if it is null.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay; // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ replayNodes.splice(j, 1);
+ break;
+ }
+}
+
+function renderChildrenArray(request, task, children, childIndex) {
+ const prevKeyPath = task.keyPath;
+
+ if (childIndex !== -1) {
+ task.keyPath = [task.keyPath, 'Fragment', childIndex];
+
+ if (task.replay !== null) {
+ replayFragment(request, // $FlowFixMe: Refined.
+ task, children, childIndex);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ const prevTreeContext = task.treeContext;
+ const totalChildren = children.length;
+
+ if (task.replay !== null) {
+ // Replay
+ // First we need to check if we have any resume slots at this level.
+ const resumeSlots = task.replay.slots;
+
+ if (resumeSlots !== null && typeof resumeSlots === 'object') {
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ const resumeSegmentID = resumeSlots[i]; // TODO: If this errors we should still continue with the next sibling.
+
+ if (typeof resumeSegmentID === 'number') {
+ resumeNode(request, task, resumeSegmentID, node, i); // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ delete resumeSlots[i];
+ } else {
+ renderNode(request, task, node, i);
+ }
+ }
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ renderNode(request, task, node, i);
+ } // Because this context is always set right before rendering every child, we
+ // only need to reset it to the previous value at the very end.
+
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+}
+
+function trackPostpone(request, trackedPostpones, task, segment) {
+ segment.status = POSTPONED;
+ const keyPath = task.keyPath;
+ const boundary = task.blockedBoundary;
+
+ if (boundary === null) {
+ segment.id = request.nextSegmentId++;
+ trackedPostpones.rootSlots = segment.id;
+
+ if (request.completedRootSegment !== null) {
+ // Postpone the root if this was a deeper segment.
+ request.completedRootSegment.status = POSTPONED;
+ }
+
+ return;
+ }
+
+ if (boundary !== null && boundary.status === PENDING) {
+ boundary.status = POSTPONED; // We need to eagerly assign it an ID because we'll need to refer to
+ // it before flushing and we know that we can't inline it.
+
+ boundary.rootSegmentID = request.nextSegmentId++;
+ const boundaryKeyPath = boundary.trackedContentKeyPath;
+
+ if (boundaryKeyPath === null) {
+ throw Error(formatProdErrorMessage(486));
+ }
+
+ const fallbackReplayNode = boundary.trackedFallbackNode;
+ const children = [];
+
+ if (boundaryKeyPath === keyPath && task.childIndex === -1) {
+ // Since we postponed directly in the Suspense boundary we can't have written anything
+ // to its segment. Therefore this will end up becoming the root segment.
+ segment.id = boundary.rootSegmentID; // We postponed directly inside the Suspense boundary so we mark this for resuming.
+
+ const boundaryNode = [boundaryKeyPath[1], boundaryKeyPath[2], children, boundary.rootSegmentID, fallbackReplayNode, boundary.rootSegmentID];
+ trackedPostpones.workingMap.set(boundaryKeyPath, boundaryNode);
+ addToReplayParent(boundaryNode, boundaryKeyPath[0], trackedPostpones);
+ return;
+ } else {
+ let boundaryNode = trackedPostpones.workingMap.get(boundaryKeyPath);
+
+ if (boundaryNode === undefined) {
+ boundaryNode = [boundaryKeyPath[1], boundaryKeyPath[2], children, null, fallbackReplayNode, boundary.rootSegmentID];
+ trackedPostpones.workingMap.set(boundaryKeyPath, boundaryNode);
+ addToReplayParent(boundaryNode, boundaryKeyPath[0], trackedPostpones);
+ } else {
+ // Upgrade to ReplaySuspenseBoundary.
+ const suspenseBoundary = boundaryNode;
+ suspenseBoundary[4] = fallbackReplayNode;
+ suspenseBoundary[5] = boundary.rootSegmentID;
+ } // Fall through to add the child node.
+
+ }
+ } // We know that this will leave a hole so we might as well assign an ID now.
+ // We might have one already if we had a parent that gave us its ID.
+
+
+ if (segment.id === -1) {
+ if (segment.parentFlushed && boundary !== null) {
+ // If this segment's parent was already flushed, it means we really just
+ // skipped the parent and this segment is now the root.
+ segment.id = boundary.rootSegmentID;
+ } else {
+ segment.id = request.nextSegmentId++;
+ }
+ }
+
+ if (task.childIndex === -1) {
+ // Resume starting from directly inside the previous parent element.
+ if (keyPath === null) {
+ trackedPostpones.rootSlots = segment.id;
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let resumableNode = workingMap.get(keyPath);
+
+ if (resumableNode === undefined) {
+ resumableNode = [keyPath[1], keyPath[2], [], segment.id];
+ addToReplayParent(resumableNode, keyPath[0], trackedPostpones);
+ } else {
+ resumableNode[3] = segment.id;
+ }
+ }
+ } else {
+ let slots;
+
+ if (keyPath === null) {
+ slots = trackedPostpones.rootSlots;
+
+ if (slots === null) {
+ slots = trackedPostpones.rootSlots = {};
+ } else if (typeof slots === 'number') {
+ throw Error(formatProdErrorMessage(491));
+ }
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let resumableNode = workingMap.get(keyPath);
+
+ if (resumableNode === undefined) {
+ slots = {};
+ resumableNode = [keyPath[1], keyPath[2], [], slots];
+ workingMap.set(keyPath, resumableNode);
+ addToReplayParent(resumableNode, keyPath[0], trackedPostpones);
+ } else {
+ slots = resumableNode[3];
+
+ if (slots === null) {
+ slots = resumableNode[3] = {};
+ } else if (typeof slots === 'number') {
+ throw Error(formatProdErrorMessage(491));
+ }
+ }
+ }
+
+ slots[task.childIndex] = segment.id;
+ }
+}
+
+function injectPostponedHole(request, task, reason) {
+ logPostpone(request, reason); // Something suspended, we'll need to create a new segment and resolve it later.
+
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ return newSegment;
+}
+
+function spawnNewSuspendedReplayTask(request, task, thenableState, x) {
+ const newTask = createReplayTask(request, thenableState, task.replay, task.node, task.childIndex, task.blockedBoundary, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+}
+
+function spawnNewSuspendedRenderTask(request, task, thenableState, x) {
+ // Something suspended, we'll need to create a new segment and resolve it later.
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ const newTask = createRenderTask(request, thenableState, task.node, task.childIndex, task.blockedBoundary, newSegment, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+} // This is a non-destructive form of rendering a node. If it suspends it spawns
+// a new task and restores the context of this task to what it was before.
+
+
+function renderNode(request, task, node, childIndex) {
+ // Snapshot the current context in case something throws to interrupt the
+ // process.
+ const previousFormatContext = task.formatContext;
+ const previousLegacyContext = task.legacyContext;
+ const previousContext = task.context;
+ const previousKeyPath = task.keyPath;
+ const previousTreeContext = task.treeContext;
+
+ let x; // Store how much we've pushed at this point so we can reset it in case something
+ // suspended partially through writing something.
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState();
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedReplayTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode.
+
+ }
+ } else {
+ // Render
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedRenderTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+
+ if (request.trackedPostpones !== null && x.$$typeof === REACT_POSTPONE_TYPE && task.blockedBoundary !== null // bubble if we're postponing in the shell
+ ) {
+ // If we're tracking postpones, we inject a hole here and continue rendering
+ // sibling. Similar to suspending. If we're not tracking, we treat it more like
+ // an error. Notably this doesn't spawn a new task since nothing will fill it
+ // in during this prerender.
+ const postponeInstance = x;
+ const trackedPostpones = request.trackedPostpones;
+ const postponedSegment = injectPostponedHole(request, task, // We don't use ReplayTasks in prerenders.
+ postponeInstance.message);
+ trackPostpone(request, trackedPostpones, task, postponedSegment); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ return;
+ }
+ }
+ }
+ } // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ // Let's terminate the rest of the tree and don't render any siblings.
+
+
+ throw x;
+}
+
+function erroredReplay(request, boundary, error, replayNodes, resumeSlots) {
+ // Erroring during a replay doesn't actually cause an error by itself because
+ // that component has already rendered. What causes the error is the resumable
+ // points that we did not yet finish which will be below the point of the reset.
+ // For example, if we're replaying a path to a Suspense boundary that is not done
+ // that doesn't error the parent Suspense boundary.
+ // This might be a bit strange that the error in a parent gets thrown at a child.
+ // We log it only once and reuse the digest.
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ abortRemainingReplayNodes(request, boundary, replayNodes, resumeSlots, error, errorDigest);
+}
+
+function erroredTask(request, boundary, error) {
+ // Report the error to a global handler.
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ if (boundary === null) {
+ fatalError(request, error);
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+ // so we can flush it, if the parent already flushed.
+
+
+ if (boundary.parentFlushed) {
+ // We don't have a preference where in the queue this goes since it's likely
+ // to error on the client anyway. However, intentionally client-rendered
+ // boundaries should be flushed earlier so that they can start on the client.
+ // We reuse the same queue for errors.
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function abortTaskSoft(task) {
+ // This aborts task without aborting the parent boundary that it blocks.
+ // It's used for when we didn't need this task to complete the tree.
+ // If task was needed, then it should use abortTask instead.
+ const request = this;
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ finishedTask(request, boundary, segment);
+ }
+}
+
+function abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest) {
+ const resumedBoundary = createSuspenseBoundary(request, new Set());
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = rootSegmentID;
+ resumedBoundary.status = CLIENT_RENDERED;
+ resumedBoundary.errorDigest = errorDigest;
+
+ if (resumedBoundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(resumedBoundary);
+ }
+}
+
+function abortRemainingReplayNodes(request, boundary, nodes, slots, error, errorDigest) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+
+ if (node.length === 4) {
+ abortRemainingReplayNodes(request, boundary, node[2], node[3], error, errorDigest);
+ } else {
+ const boundaryNode = node;
+ const rootSegmentID = boundaryNode[5];
+ abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest);
+ }
+ } // Empty the set, since we've cleared it now.
+
+
+ nodes.length = 0;
+
+ if (slots !== null) {
+ // We had something still to resume in the parent boundary. We must trigger
+ // the error on the parent boundary since it's not able to complete.
+ if (boundary === null) {
+ throw Error(formatProdErrorMessage(487));
+ } else if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // Empty the set
+
+
+ if (typeof slots === 'object') {
+ for (const index in slots) {
+ delete slots[index];
+ }
+ }
+ }
+}
+
+function abortTask(task, request, error) {
+ // This aborts the task and aborts the parent that it blocks, putting it into
+ // client rendered mode.
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ }
+
+ if (boundary === null) {
+ if (request.status !== CLOSING && request.status !== CLOSED) {
+ const replay = task.replay;
+
+ if (replay === null) {
+ // We didn't complete the root so we have nothing to show. We can close
+ // the request;
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ return;
+ } else {
+ // If the shell aborts during a replay, that's not a fatal error. Instead
+ // we should be able to recover by client rendering all the root boundaries in
+ // the ReplaySet.
+ replay.pendingTasks--;
+
+ if (replay.pendingTasks === 0 && replay.nodes.length > 0) {
+ const errorDigest = logRecoverableError(request, error);
+ abortRemainingReplayNodes(request, null, replay.nodes, replay.slots, error, errorDigest);
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ }
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = logRecoverableError(request, error);
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // If this boundary was still pending then we haven't already cancelled its fallbacks.
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
+
+
+ boundary.fallbackAbortableTasks.forEach(fallbackTask => abortTask(fallbackTask, request, error));
+ boundary.fallbackAbortableTasks.clear();
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeShell(request) {
+ if (request.trackedPostpones === null) {
+ // We only emit early preloads on shell completion for renders. For prerenders
+ // we wait for the entire Request to finish because we are not responding to a
+ // live request and can wait for as much data as possible.
+ // we should only be calling completeShell when the shell is complete so we
+ // just use a literal here
+ const shellComplete = true;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ } // We have completed the shell so the shell can't error anymore.
+
+
+ request.onShellError = noop;
+ const onShellReady = request.onShellReady;
+ onShellReady();
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeAll(request) {
+ // During a render the shell must be complete if the entire request is finished
+ // however during a Prerender it is possible that the shell is incomplete because
+ // it postponed. We cannot use rootPendingTasks in the prerender case because
+ // those hit zero even when the shell postpones. Instead we look at the completedRootSegment
+ const shellComplete = request.trackedPostpones === null ? // Render, we assume it is completed
+ true : // Prerender Request, we use the state of the root segment
+ request.completedRootSegment === null || request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ const onAllReady = request.onAllReady;
+ onAllReady();
+}
+
+function queueCompletedSegment(boundary, segment) {
+ if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) {
+ // This is an empty segment. There's nothing to write, so we can instead transfer the ID
+ // to the child. That way any existing references point to the child.
+ const childSegment = segment.children[0];
+ childSegment.id = segment.id;
+ childSegment.parentFlushed = true;
+
+ if (childSegment.status === COMPLETED) {
+ queueCompletedSegment(boundary, childSegment);
+ }
+ } else {
+ const completedSegments = boundary.completedSegments;
+ completedSegments.push(segment);
+ }
+}
+
+function finishedTask(request, boundary, segment) {
+ if (boundary === null) {
+ if (segment !== null && segment.parentFlushed) {
+ if (request.completedRootSegment !== null) {
+ throw Error(formatProdErrorMessage(389));
+ }
+
+ request.completedRootSegment = segment;
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status === CLIENT_RENDERED) ; else if (boundary.pendingTasks === 0) {
+ if (boundary.status === PENDING) {
+ boundary.status = COMPLETED;
+ } // This must have been the last segment we were waiting on. This boundary is now complete.
+
+
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent segment already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ }
+ }
+
+ if (boundary.parentFlushed) {
+ // The segment might be part of a segment that didn't flush yet, but if the boundary's
+ // parent flushed, we need to schedule the boundary to be emitted.
+ request.completedBoundaries.push(boundary);
+ } // We can now cancel any pending task on the fallback since we won't need to show it anymore.
+ // This needs to happen after we read the parentFlushed flags because aborting can finish
+ // work which can trigger user code, which can start flushing, which can change those flags.
+ // If the boundary was POSTPONED, we still need to finish the fallback first.
+
+
+ if (boundary.status === COMPLETED) {
+ boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
+ boundary.fallbackAbortableTasks.clear();
+ }
+ } else {
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length === 1) {
+ // This is the first time since we last flushed that we completed anything.
+ // We can schedule this boundary to emit its partially completed segments early
+ // in case the parent has already been flushed.
+ if (boundary.parentFlushed) {
+ request.partialBoundaries.push(boundary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function retryTask(request, task) {
+ {
+ const blockedBoundary = task.blockedBoundary;
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, blockedBoundary ? blockedBoundary.resources : null);
+ }
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ retryReplayTask(request, // $FlowFixMe: Refined.
+ task);
+ } else {
+ retryRenderTask(request, // $FlowFixMe: Refined.
+ task, segment);
+ }
+}
+
+function retryRenderTask(request, task, segment) {
+ if (segment.status !== PENDING) {
+ // We completed this by other means before we had a chance to retry it.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+ pushSegmentFinale(segment.chunks, request.renderState, segment.lastPushedText, segment.textEmbedded);
+ task.abortSet.delete(task);
+ segment.status = COMPLETED;
+ finishedTask(request, task.blockedBoundary, segment);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ } else if (request.trackedPostpones !== null && x.$$typeof === REACT_POSTPONE_TYPE) {
+ // If we're tracking postpones, we mark this segment as postponed and finish
+ // the task without filling it in. If we're not tracking, we treat it more like
+ // an error.
+ const trackedPostpones = request.trackedPostpones;
+ task.abortSet.delete(task);
+ const postponeInstance = x;
+ logPostpone(request, postponeInstance.message);
+ trackPostpone(request, trackedPostpones, task, segment);
+ finishedTask(request, task.blockedBoundary, segment);
+ return;
+ }
+ }
+
+ task.abortSet.delete(task);
+ segment.status = ERRORED;
+ erroredTask(request, task.blockedBoundary, x);
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function retryReplayTask(request, task) {
+ if (task.replay.pendingTasks === 0) {
+ // There are no pending tasks working on this set, so we must have aborted.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ finishedTask(request, task.blockedBoundary, null);
+ } catch (thrownValue) {
+ resetHooksState();
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ erroredReplay(request, task.blockedBoundary, x, task.replay.nodes, task.replay.slots);
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function performWork(request) {
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ const prevContext = getActiveContext();
+ const prevDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = HooksDispatcher;
+ let prevCacheDispatcher;
+
+ {
+ prevCacheDispatcher = ReactCurrentCache.current;
+ ReactCurrentCache.current = DefaultCacheDispatcher;
+ }
+
+ const prevRequest = currentRequest;
+ currentRequest = request;
+
+ const prevResumableState = currentResumableState;
+ setCurrentResumableState(request.resumableState);
+
+ try {
+ const pingedTasks = request.pingedTasks;
+ let i;
+
+ for (i = 0; i < pingedTasks.length; i++) {
+ const task = pingedTasks[i];
+ retryTask(request, task);
+ }
+
+ pingedTasks.splice(0, i);
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ } finally {
+ setCurrentResumableState(prevResumableState);
+ ReactCurrentDispatcher.current = prevDispatcher;
+
+ {
+ ReactCurrentCache.current = prevCacheDispatcher;
+ }
+
+ if (prevDispatcher === HooksDispatcher) {
+ // This means that we were in a reentrant work loop. This could happen
+ // in a renderer that supports synchronous work like renderToString,
+ // when it's called from within another renderer.
+ // Normally we don't bother switching the contexts to their root/default
+ // values when leaving because we'll likely need the same or similar
+ // context again. However, when we're inside a synchronous loop like this
+ // we'll to restore the context to what it was before returning.
+ switchContext(prevContext);
+ }
+
+ currentRequest = prevRequest;
+ }
+}
+
+function flushSubtree(request, destination, segment) {
+ segment.parentFlushed = true;
+
+ switch (segment.status) {
+ case PENDING:
+ {
+ // We're emitting a placeholder for this segment to be filled in later.
+ // Therefore we'll need to assign it an ID - to refer to it by.
+ segment.id = request.nextSegmentId++; // Fallthrough
+ }
+
+ case POSTPONED:
+ {
+ const segmentID = segment.id; // When this segment finally completes it won't be embedded in text since it will flush separately
+
+ segment.lastPushedText = false;
+ segment.textEmbedded = false;
+ return writePlaceholder(destination, request.renderState, segmentID);
+ }
+
+ case COMPLETED:
+ {
+ segment.status = FLUSHED;
+ let r = true;
+ const chunks = segment.chunks;
+ let chunkIdx = 0;
+ const children = segment.children;
+
+ for (let childIdx = 0; childIdx < children.length; childIdx++) {
+ const nextChild = children[childIdx]; // Write all the chunks up until the next child.
+
+ for (; chunkIdx < nextChild.index; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ r = flushSegment(request, destination, nextChild);
+ } // Finally just write all the remaining chunks
+
+
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ if (chunkIdx < chunks.length) {
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
+ }
+
+ return r;
+ }
+
+ default:
+ {
+ throw Error(formatProdErrorMessage(390));
+ }
+ }
+}
+
+function flushSegment(request, destination, segment) {
+ const boundary = segment.boundary;
+
+ if (boundary === null) {
+ // Not a suspense boundary.
+ return flushSubtree(request, destination, segment);
+ }
+
+ boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to
+ // emit the content or the fallback now.
+
+ if (boundary.status === CLIENT_RENDERED) {
+ // Emit a client rendered suspense boundary wrapper.
+ // We never queue the inner boundary so we'll never emit its content or partial segments.
+ writeStartClientRenderedSuspenseBoundary(destination, request.renderState, boundary.errorDigest); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndClientRenderedSuspenseBoundary(destination);
+ } else if (boundary.status !== COMPLETED) {
+ if (boundary.status === PENDING) {
+ // For pending boundaries we lazily assign an ID to the boundary
+ // and root segment.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ }
+
+ if (boundary.completedSegments.length > 0) {
+ // If this is at least partially complete, we can queue it to be partially emitted early.
+ request.partialBoundaries.push(boundary);
+ } // This boundary is still loading. Emit a pending suspense boundary wrapper.
+
+
+ const id = boundary.rootSegmentID;
+ writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else if (boundary.byteSize > request.progressiveChunkSize) {
+ // This boundary is large and will be emitted separately so that we can progressively show
+ // other content. We add it to the queue during the flush because we have to ensure that
+ // the parent flushes first so that there's something to inject it into.
+ // We also have to make sure that it's emitted into the queue in a deterministic slot.
+ // I.e. we can't insert it here when it completes.
+ // Assign an ID to refer to the future content by.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper.
+
+ writeStartPendingSuspenseBoundary(destination, request.renderState, boundary.rootSegmentID); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else {
+ {
+ hoistResources(request.renderState, boundary.resources);
+ } // We can inline this boundary's content as a complete boundary.
+
+
+ writeStartCompletedSuspenseBoundary(destination);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length !== 1) {
+ throw Error(formatProdErrorMessage(391));
+ }
+
+ const contentSegment = completedSegments[0];
+ flushSegment(request, destination, contentSegment);
+ return writeEndCompletedSuspenseBoundary(destination);
+ }
+}
+
+function flushClientRenderedBoundary(request, destination, boundary) {
+ return writeClientRenderBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack);
+}
+
+function flushSegmentContainer(request, destination, segment) {
+ writeStartSegment(destination, request.renderState, segment.parentFormatContext, segment.id);
+ flushSegment(request, destination, segment);
+ return writeEndSegment(destination, segment.parentFormatContext);
+}
+
+function flushCompletedBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+ flushPartiallyCompletedSegment(request, destination, boundary, segment);
+ }
+
+ completedSegments.length = 0;
+
+ {
+ writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+
+ return writeCompletedBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.resources);
+}
+
+function flushPartialBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+
+ if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) {
+ i++;
+ completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority
+ // might want to write later.
+
+ return false;
+ }
+ }
+
+ completedSegments.splice(0, i);
+
+ {
+ // The way this is structured we only write resources for partial boundaries
+ // if there is no backpressure. Later before we complete the boundary we
+ // will write resources regardless of backpressure before we emit the
+ // completion instruction
+ return writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+}
+
+function flushPartiallyCompletedSegment(request, destination, boundary, segment) {
+ if (segment.status === FLUSHED) {
+ // We've already flushed this inline.
+ return true;
+ }
+
+ const segmentID = segment.id;
+
+ if (segmentID === -1) {
+ // This segment wasn't previously referred to. This happens at the root of
+ // a boundary. We make kind of a leap here and assume this is the root.
+ const rootSegmentID = segment.id = boundary.rootSegmentID;
+
+ if (rootSegmentID === -1) {
+ throw Error(formatProdErrorMessage(392));
+ }
+
+ return flushSegmentContainer(request, destination, segment);
+ } else if (segmentID === boundary.rootSegmentID) {
+ // When we emit postponed boundaries, we might have assigned the ID already
+ // but it's still the root segment so we can't inject it into the parent yet.
+ return flushSegmentContainer(request, destination, segment);
+ } else {
+ flushSegmentContainer(request, destination, segment);
+ return writeCompletedSegmentInstruction(destination, request.resumableState, request.renderState, segmentID);
+ }
+}
+
+function flushCompletedQueues(request, destination) {
+ beginWriting();
+
+ try {
+ // The structure of this is to go through each queue one by one and write
+ // until the sink tells us to stop. When we should stop, we still finish writing
+ // that item fully and then yield. At that point we remove the already completed
+ // items up until the point we completed them.
+ let i;
+ const completedRootSegment = request.completedRootSegment;
+
+ if (completedRootSegment !== null) {
+ if (completedRootSegment.status === POSTPONED) {
+ // We postponed the root, so we write nothing.
+ return;
+ } else if (request.pendingRootTasks === 0) {
+ if (enableFloat) {
+ writePreamble(destination, request.resumableState, request.renderState, request.allPendingTasks === 0 && request.trackedPostpones === null);
+ }
+
+ flushSegment(request, destination, completedRootSegment);
+ request.completedRootSegment = null;
+ writeCompletedRoot(destination, request.renderState, request.resumableState);
+ } else {
+ // We haven't flushed the root yet so we don't need to check any other branches further down
+ return;
+ }
+ }
+
+ if (enableFloat) {
+ writeHoistables(destination, request.resumableState, request.renderState);
+ } // We emit client rendering instructions for already emitted boundaries first.
+ // This is so that we can signal to the client to start client rendering them as
+ // soon as possible.
+
+
+ const clientRenderedBoundaries = request.clientRenderedBoundaries;
+
+ for (i = 0; i < clientRenderedBoundaries.length; i++) {
+ const boundary = clientRenderedBoundaries[i];
+
+ if (!flushClientRenderedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ clientRenderedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries
+ // that are completely done since we can actually show them, than it is to emit
+ // any individual segments from a partially complete boundary.
+
+ const completedBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < completedBoundaries.length; i++) {
+ const boundary = completedBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ completedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before
+ // we continue with lower priorities.
+
+ completeWriting(destination);
+ beginWriting(destination); // TODO: Here we'll emit data used by hydration.
+ // Next we emit any segments of any boundaries that are partially complete
+ // but not deeply complete.
+
+ const partialBoundaries = request.partialBoundaries;
+
+ for (i = 0; i < partialBoundaries.length; i++) {
+ const boundary = partialBoundaries[i];
+
+ if (!flushPartialBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ partialBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had
+ // boundaries added to it in case they were too larged to be inlined.
+ // New ones might be added in this loop.
+
+ const largeBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < largeBoundaries.length; i++) {
+ const boundary = largeBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ largeBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ largeBoundaries.splice(0, i);
+ } finally {
+ if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because
+ // either they have pending task or they're complete.
+ ) {
+ request.flushScheduled = false;
+
+ {
+ // We write the trailing tags but only if don't have any data to resume.
+ // If we need to resume we'll write the postamble in the resume instead.
+ if (request.trackedPostpones === null) {
+ writePostamble(destination, request.resumableState);
+ }
+ }
+
+ completeWriting(destination);
+
+
+ close(destination); // We need to stop flowing now because we do not want any async contexts which might call
+ // float methods to initiate any flushes after this point
+
+ stopFlowing(request);
+ } else {
+ completeWriting(destination);
+ }
+ }
+}
+
+function startWork(request) {
+ request.flushScheduled = request.destination !== null;
+
+ {
+ scheduleWork(() => performWork(request));
+ }
+
+ if (request.trackedPostpones === null) {
+ // this is either a regular render or a resume. For regular render we want
+ // to call emitEarlyPreloads after the first performWork because we want
+ // are responding to a live request and need to balance sending something early
+ // (i.e. don't want for the shell to finish) but we need something to send.
+ // The only implementation of this is for DOM at the moment and during resumes nothing
+ // actually emits but the code paths here are the same.
+ // During a prerender we don't want to be too aggressive in emitting early preloads
+ // because we aren't responding to a live request and we can wait for the prerender to
+ // postpone before we emit anything.
+ {
+ scheduleWork(() => enqueueEarlyPreloadsAfterInitialWork(request));
+ }
+ }
+}
+
+function enqueueEarlyPreloadsAfterInitialWork(request) {
+ const shellComplete = request.pendingRootTasks === 0;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+
+function enqueueFlush(request) {
+ if (request.flushScheduled === false && // If there are pinged tasks we are going to flush anyway after work completes
+ request.pingedTasks.length === 0 && // If there is no destination there is nothing we can flush to. A flush will
+ // happen when we start flowing again
+ request.destination !== null) {
+ request.flushScheduled = true;
+ scheduleWork(() => {
+ // We need to existence check destination again here because it might go away
+ // in between the enqueueFlush call and the work execution
+ const destination = request.destination;
+
+ if (destination) {
+ flushCompletedQueues(request, destination);
+ } else {
+ request.flushScheduled = false;
+ }
+ });
+ }
+} // This function is intented to only be called during the pipe function for the Node builds.
+function startFlowing(request, destination) {
+ if (request.status === CLOSING) {
+ request.status = CLOSED;
+ closeWithError(destination, request.fatalError);
+ return;
+ }
+
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ if (request.destination !== null) {
+ // We're already flowing.
+ return;
+ }
+
+ request.destination = destination;
+
+ try {
+ flushCompletedQueues(request, destination);
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function stopFlowing(request) {
+ request.destination = null;
+} // This is called to early terminate a request. It puts all pending boundaries in client rendered state.
+
+function abort(request, reason) {
+ try {
+ const abortableTasks = request.abortableTasks;
+
+ if (abortableTasks.size > 0) {
+ const error = reason === undefined ? Error(formatProdErrorMessage(432)) : reason;
+ abortableTasks.forEach(task => abortTask(task, request, error));
+ abortableTasks.clear();
+ }
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function flushResources(request) {
+ enqueueFlush(request);
+}
+function getFormState(request) {
+ return request.formState;
+}
+function getResumableState(request) {
+ return request.resumableState;
+}
+function getRenderState(request) {
+ return request.renderState;
+}
+
+function addToReplayParent(node, parentKeyPath, trackedPostpones) {
+ if (parentKeyPath === null) {
+ trackedPostpones.rootNodes.push(node);
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let parentNode = workingMap.get(parentKeyPath);
+
+ if (parentNode === undefined) {
+ parentNode = [parentKeyPath[1], parentKeyPath[2], [], null];
+ workingMap.set(parentKeyPath, parentNode);
+ addToReplayParent(parentNode, parentKeyPath[0], trackedPostpones);
+ }
+
+ parentNode[2].push(node);
+ }
+} // Returns the state of a postponed request or null if nothing was postponed.
+
+
+function getPostponedState(request) {
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones === null || trackedPostpones.rootNodes.length === 0 && trackedPostpones.rootSlots === null) {
+ // Reset. Let the flushing behave as if we completed the whole document.
+ request.trackedPostpones = null;
+ return null;
+ }
+
+ if (request.completedRootSegment !== null && request.completedRootSegment.status === POSTPONED) {
+ // We postponed the root so we didn't flush anything.
+ resetResumableState(request.resumableState, request.renderState);
+ }
+
+ return {
+ nextSegmentId: request.nextSegmentId,
+ rootFormatContext: request.rootFormatContext,
+ progressiveChunkSize: request.progressiveChunkSize,
+ resumableState: request.resumableState,
+ replayNodes: trackedPostpones.rootNodes,
+ replaySlots: trackedPostpones.rootSlots
+ };
+}
+
+function renderToReadableStream(children, options) {
+ return new Promise((resolve, reject) => {
+ let onFatalError;
+ let onAllReady;
+ const allReady = new Promise((res, rej) => {
+ onAllReady = res;
+ onFatalError = rej;
+ });
+
+ function onShellReady() {
+ const stream = new ReadableStream({
+ type: 'bytes',
+ pull: controller => {
+ startFlowing(request, controller);
+ },
+ cancel: reason => {
+ stopFlowing(request);
+ abort(request, reason);
+ }
+ }, // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
+ {
+ highWaterMark: 0
+ }); // TODO: Move to sub-classing ReadableStream.
+
+ stream.allReady = allReady;
+ resolve(stream);
+ }
+
+ function onShellError(error) {
+ // If the shell errors the caller of `renderToReadableStream` won't have access to `allReady`.
+ // However, `allReady` will be rejected by `onFatalError` as well.
+ // So we need to catch the duplicate, uncatchable fatal error in `allReady` to prevent a `UnhandledPromiseRejection`.
+ allReady.catch(() => {});
+ reject(error);
+ }
+
+ const onHeaders = options ? options.onHeaders : undefined;
+ let onHeadersImpl;
+
+ if (onHeaders) {
+ onHeadersImpl = headersDescriptor => {
+ onHeaders(new Headers(headersDescriptor));
+ };
+ }
+
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ const request = createRequest(children, resumableState, createRenderState(resumableState, options ? options.nonce : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, onHeadersImpl, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, onAllReady, onShellReady, onShellError, onFatalError, options ? options.onPostpone : undefined, options ? options.formState : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+function resume(children, postponedState, options) {
+ return new Promise((resolve, reject) => {
+ let onFatalError;
+ let onAllReady;
+ const allReady = new Promise((res, rej) => {
+ onAllReady = res;
+ onFatalError = rej;
+ });
+
+ function onShellReady() {
+ const stream = new ReadableStream({
+ type: 'bytes',
+ pull: controller => {
+ startFlowing(request, controller);
+ },
+ cancel: reason => {
+ stopFlowing(request);
+ abort(request, reason);
+ }
+ }, // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
+ {
+ highWaterMark: 0
+ }); // TODO: Move to sub-classing ReadableStream.
+
+ stream.allReady = allReady;
+ resolve(stream);
+ }
+
+ function onShellError(error) {
+ // If the shell errors the caller of `renderToReadableStream` won't have access to `allReady`.
+ // However, `allReady` will be rejected by `onFatalError` as well.
+ // So we need to catch the duplicate, uncatchable fatal error in `allReady` to prevent a `UnhandledPromiseRejection`.
+ allReady.catch(() => {});
+ reject(error);
+ }
+
+ const request = resumeRequest(children, postponedState, resumeRenderState(postponedState.resumableState, options ? options.nonce : undefined), options ? options.onError : undefined, onAllReady, onShellReady, onShellError, onFatalError, options ? options.onPostpone : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+function prerender(children, options) {
+ return new Promise((resolve, reject) => {
+ const onFatalError = reject;
+
+ function onAllReady() {
+ const stream = new ReadableStream({
+ type: 'bytes',
+ pull: controller => {
+ startFlowing(request, controller);
+ },
+ cancel: reason => {
+ stopFlowing(request);
+ abort(request, reason);
+ }
+ }, // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
+ {
+ highWaterMark: 0
+ });
+ const result = {
+ postponed: getPostponedState(request),
+ prelude: stream
+ };
+ resolve(result);
+ }
+
+ const onHeaders = options ? options.onHeaders : undefined;
+ let onHeadersImpl;
+
+ if (onHeaders) {
+ onHeadersImpl = headersDescriptor => {
+ onHeaders(new Headers(headersDescriptor));
+ };
+ }
+
+ const resources = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ const request = createPrerenderRequest(children, resources, createRenderState(resources, undefined, // nonce is not compatible with prerendered bootstrap scripts
+ options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, onHeadersImpl, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, onAllReady, undefined, undefined, onFatalError, options ? options.onPostpone : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+exports.prerender = prerender;
+exports.renderToReadableStream = renderToReadableStream;
+exports.resume = resume;
+exports.version = ReactVersion;
\ No newline at end of file
diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.production.min.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.production.min.js
index 11d7b2f83d6df..c7ff75f41e179 100644
--- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.production.min.js
+++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.production.min.js
@@ -1,13 +1,11 @@
-/**
- * @license React
- * react-dom-server.browser.production.min.js
- *
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
/*
+ React
+ react-dom-server.browser.production.min.js
+
+ Copyright (c) Meta Platforms, Inc. and affiliates.
+
+ This source code is licensed under the MIT license found in the
+ LICENSE file in the root directory of this source tree.
JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
@@ -33,8 +31,8 @@
*/
'use strict';var da=require("next/dist/compiled/react-experimental"),ea=require("react-dom");function l(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;c>>16)&65535)<<16)&4294967295;f=f<<15|f>>>17;f=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295;e^=f;e=e<<13|e>>>19;e=5*(e&65535)+((5*(e>>>16)&65535)<<16)&4294967295;e=(e&65535)+27492+(((e>>>16)+58964&65535)<<16)}f=0;switch(c){case 3:f^=(a.charCodeAt(b+2)&255)<<
-16;case 2:f^=(a.charCodeAt(b+1)&255)<<8;case 1:f^=a.charCodeAt(b)&255,f=3432918353*(f&65535)+((3432918353*(f>>>16)&65535)<<16)&4294967295,f=f<<15|f>>>17,e^=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295}e^=a.length;e^=e>>>16;e=2246822507*(e&65535)+((2246822507*(e>>>16)&65535)<<16)&4294967295;e^=e>>>13;e=3266489909*(e&65535)+((3266489909*(e>>>16)&65535)<<16)&4294967295;return(e^e>>>16)>>>0}var n=null,r=0;
-function v(a,b){if(0!==b.byteLength)if(512>>16)&65535)<<16)&4294967295,f=f<<15|f>>>17,e^=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295}e^=a.length;e^=e>>>16;e=2246822507*(e&65535)+((2246822507*(e>>>16)&65535)<<16)&4294967295;e^=e>>>13;e=3266489909*(e&65535)+((3266489909*(e>>>16)&65535)<<16)&4294967295;return(e^e>>>16)>>>0}var n=null,q=0;
+function v(a,b){if(0!==b.byteLength)if(512 '),db=A("');
+const startScriptSrc = stringToPrecomputedChunk('');
+/**
+ * This escaping function is designed to work with bootstrapScriptContent and importMap only.
+ * because we know we are escaping the entire script. We can avoid for instance
+ * escaping html comment string sequences that are valid javascript as well because
+ * if there are no sebsequent '); // Since we store headers as strings we deal with their length in utf16 code units
+// rather than visual characters or the utf8 encoding that is used for most binary
+// serialization. Some common HTTP servers only allow for headers to be 4kB in length.
+// We choose a default length that is likely to be well under this already limited length however
+// pathological cases may still cause the utf-8 encoding of the headers to approach this limit.
+// It should also be noted that this maximum is a soft maximum. we have not reached the limit we will
+// allow one more header to be captured which means in practice if the limit is approached it will be exceeded
+
+const DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep track of what we've already written so we can refer back to it.
+// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
+// is set, the server will send instructions via data attributes (instead of inline scripts)
+
+function createRenderState(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+ const inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const completeSegmentData1 = stringToPrecomputedChunk('');
+const completeBoundaryData1 = stringToPrecomputedChunk('');
+const clientRenderData1 = stringToPrecomputedChunk('
+ return writeChunkAndReturn(destination, clientRenderDataEnd);
+ }
+}
+const regexForJSStringsInInstructionScripts = /[<\u2028\u2029]/g;
+
+function escapeJSStringsForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInInstructionScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const regexForJSStringsInScripts = /[&><\u2028\u2029]/g;
+
+function escapeJSObjectForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '&':
+ return '\\u0026';
+
+ case '>':
+ return '\\u003e';
+
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(''); // Tracks whether the boundary currently flushing is flushign style tags or has any
+// stylesheet dependencies not flushed in the Preamble.
+
+let currentlyRenderingBoundaryHasStylesToHoist = false; // Acts as a return value for the forEach execution of style tag flushing.
+
+let destinationHasCapacity = true;
+
+function flushStyleTagsLateForBoundary(styleQueue) {
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs;
+
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, lateStyleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ writeChunk(this, lateStyleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, lateStyleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ destinationHasCapacity = writeChunkAndReturn(this, lateStyleTagTemplateClose); // We wrote style tags for this boundary and we may need to emit a script
+ // to hoist them.
+
+ currentlyRenderingBoundaryHasStylesToHoist = true; // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function hasStylesToHoist(stylesheet) {
+ // We need to reveal boundaries with styles whenever a stylesheet it depends on is either
+ // not flushed or flushed after the preamble (shell).
+ if (stylesheet.state !== PREAMBLE) {
+ currentlyRenderingBoundaryHasStylesToHoist = true;
+ return true;
+ }
+
+ return false;
+}
+
+function writeResourcesForBoundary(destination, boundaryResources, renderState) {
+ // Reset these on each invocation, they are only safe to read in this function
+ currentlyRenderingBoundaryHasStylesToHoist = false;
+ destinationHasCapacity = true; // Flush style tags for each precedence this boundary depends on
+
+ boundaryResources.styles.forEach(flushStyleTagsLateForBoundary, destination); // Determine if this boundary has stylesheets that need to be awaited upon completion
+
+ boundaryResources.stylesheets.forEach(hasStylesToHoist);
+
+ if (currentlyRenderingBoundaryHasStylesToHoist) {
+ renderState.stylesToHoist = true;
+ }
+
+ return destinationHasCapacity;
+}
+
+function flushResource(resource) {
+ for (let i = 0; i < resource.length; i++) {
+ writeChunk(this, resource[i]);
+ }
+
+ resource.length = 0;
+}
+
+const stylesheetFlushingQueue = [];
+
+function flushStyleInPreamble(stylesheet, key, map) {
+ // We still need to encode stylesheet chunks
+ // because unlike most Hoistables and Resources we do not eagerly encode
+ // them during render. This is because if we flush late we have to send a
+ // different encoding and we don't want to encode multiple times
+ pushLinkImpl(stylesheetFlushingQueue, stylesheet.props);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ stylesheet.state = PREAMBLE;
+}
+
+const styleTagResourceOpen1 = stringToPrecomputedChunk('');
+
+function flushStylesInPreamble(styleQueue, precedence) {
+ const hasStylesheets = styleQueue.sheets.size > 0;
+ styleQueue.sheets.forEach(flushStyleInPreamble, this);
+ styleQueue.sheets.clear();
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs; // If we don't emit any stylesheets at this precedence we still need to maintain the precedence
+ // order so even if there are no rules for style tags at this precedence we emit an empty style
+ // tag with the data-precedence attribute
+
+ if (!hasStylesheets || hrefs.length) {
+ writeChunk(this, styleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, styleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ }
+
+ writeChunk(this, styleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ writeChunk(this, styleTagResourceClose); // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function preloadLateStyle(stylesheet) {
+ if (stylesheet.state === PENDING$1) {
+ stylesheet.state = PRELOADED;
+ const preloadProps = preloadAsStylePropsFromProps(stylesheet.props.href, stylesheet.props);
+ pushLinkImpl(stylesheetFlushingQueue, preloadProps);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ }
+}
+
+function preloadLateStyles(styleQueue) {
+ styleQueue.sheets.forEach(preloadLateStyle, this);
+ styleQueue.sheets.clear();
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+
+function writePreamble(destination, resumableState, renderState, willFlushAllSegments) {
+ // This function must be called exactly once on every request
+ if (!willFlushAllSegments && renderState.externalRuntimeScript) {
+ // If the root segment is incomplete due to suspended tasks
+ // (e.g. willFlushAllSegments = false) and we are using data
+ // streaming format, ensure the external runtime is sent.
+ // (User code could choose to send this even earlier by calling
+ // preinit(...), if they know they will suspend).
+ const _renderState$external = renderState.externalRuntimeScript,
+ src = _renderState$external.src,
+ chunks = _renderState$external.chunks;
+ internalPreinitScript(resumableState, renderState, src, chunks);
+ }
+
+ const htmlChunks = renderState.htmlChunks;
+ const headChunks = renderState.headChunks;
+ let i = 0; // Emit open tags before Hoistables and Resources
+
+ if (htmlChunks) {
+ // We have an to emit as part of the preamble
+ for (i = 0; i < htmlChunks.length; i++) {
+ writeChunk(destination, htmlChunks[i]);
+ }
+
+ if (headChunks) {
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } else {
+ // We did not render a head but we emitted an so we emit one now
+ writeChunk(destination, startChunkForTag('head'));
+ writeChunk(destination, endOfStartTag);
+ }
+ } else if (headChunks) {
+ // We do not have an but we do have a
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } // Emit high priority Hoistables
+
+
+ const charsetChunks = renderState.charsetChunks;
+
+ for (i = 0; i < charsetChunks.length; i++) {
+ writeChunk(destination, charsetChunks[i]);
+ }
+
+ charsetChunks.length = 0; // emit preconnect resources
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Flush unblocked stylesheets by precedence
+
+ renderState.styles.forEach(flushStylesInPreamble, destination);
+ const importMapChunks = renderState.importMapChunks;
+
+ for (i = 0; i < importMapChunks.length; i++) {
+ writeChunk(destination, importMapChunks[i]);
+ }
+
+ importMapChunks.length = 0;
+ renderState.bootstrapScripts.forEach(flushResource, destination);
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0; // Flush closing head if necessary
+
+ if (htmlChunks && headChunks === null) {
+ // We have an rendered but no rendered. We however inserted
+ // a up above so we need to emit the now. This is safe because
+ // if the main content contained the it would also have provided a
+ // . This means that all the content inside is either or
+ // invalid HTML
+ writeChunk(destination, endChunkForTag('head'));
+ }
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+function writeHoistables(destination, resumableState, renderState) {
+ let i = 0; // Emit high priority Hoistables
+ // We omit charsetChunks because we have already sent the shell and if it wasn't
+ // already sent it is too late now.
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Preload any stylesheets. these will emit in a render instruction that follows this
+ // but we want to kick off preloading as soon as possible
+
+ renderState.styles.forEach(preloadLateStyles, destination); // We only hoist importmaps that are configured through createResponse and that will
+ // always flush in the preamble. Generally we don't expect people to render them as
+ // tags when using React but if you do they are going to be treated like regular inline
+ // scripts and flush after other hoistables which is problematic
+ // bootstrap scripts should flush above script priority but these can only flush in the preamble
+ // so we elide the code here for performance
+
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0;
+}
+function writePostamble(destination, resumableState) {
+ if (resumableState.hasBody) {
+ writeChunk(destination, endChunkForTag('body'));
+ }
+
+ if (resumableState.hasHtml) {
+ writeChunk(destination, endChunkForTag('html'));
+ }
+}
+const arrayFirstOpenBracket = stringToPrecomputedChunk('[');
+const arraySubsequentOpenBracket = stringToPrecomputedChunk(',[');
+const arrayInterstitial = stringToPrecomputedChunk(',');
+const arrayCloseBracket = stringToPrecomputedChunk(']'); // This function writes a 2D array of strings to be embedded in javascript.
+// E.g.
+// [["JS_escaped_string1", "JS_escaped_string2"]]
+
+function writeStyleResourceDependenciesInJS(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInJS(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInJS(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInJS(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+}
+
+function writeStyleResourceDependencyInJS(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedPrecedence)));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInJS(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInJS(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeName)));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeValue)));
+} // This function writes a 2D array of strings to be embedded in an attribute
+// value and read with JSON.parse in ReactDOMServerExternalRuntime.js
+// E.g.
+// [["JSON_escaped_string1", "JSON_escaped_string2"]]
+
+
+function writeStyleResourceDependenciesInAttr(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInAttr(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInAttr(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInAttr(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+}
+
+function writeStyleResourceDependencyInAttr(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedPrecedence))));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInAttr(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInAttr(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeName))));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeValue))));
+}
+/**
+ * Resources
+ */
+
+
+const PENDING$1 = 0;
+const PRELOADED = 1;
+const PREAMBLE = 2;
+const LATE = 3;
+function createBoundaryResources() {
+ return {
+ styles: new Set(),
+ stylesheets: new Set()
+ };
+}
+function setCurrentlyRenderingBoundaryResourcesTarget(renderState, boundaryResources) {
+ renderState.boundaryResources = boundaryResources;
+}
+
+function getResourceKey(href) {
+ return href;
+}
+
+function getImageResourceKey(href, imageSrcSet, imageSizes) {
+ if (imageSrcSet) {
+ return imageSrcSet + '\n' + (imageSizes || '');
+ }
+
+ return href;
+}
+
+function prefetchDNS(href) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const key = getResourceKey(href);
+
+ if (!resumableState.dnsResources.hasOwnProperty(key)) {
+ resumableState.dnsResources[key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPrefetchDNSAsHeader(href), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this as resettable in case we are prerendering and postpone in the Shell
+ renderState.resets.dns[key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ // Encode as element
+ const resource = [];
+ pushLinkImpl(resource, {
+ href,
+ rel: 'dns-prefetch'
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preconnect(href, crossOrigin) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const bucket = crossOrigin === 'use-credentials' ? 'credentials' : typeof crossOrigin === 'string' ? 'anonymous' : 'default';
+ const key = getResourceKey(href);
+
+ if (!resumableState.connectResources[bucket].hasOwnProperty(key)) {
+ resumableState.connectResources[bucket][key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreconnectAsHeader(href, crossOrigin), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this in resettableState in case we are prerending and postpone in the Shell
+ renderState.resets.connect[bucket][key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ const resource = [];
+ pushLinkImpl(resource, {
+ rel: 'preconnect',
+ href,
+ crossOrigin
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preload(href, as, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (as && href) {
+ switch (as) {
+ case 'image':
+ {
+ let imageSrcSet, imageSizes, fetchPriority;
+
+ if (options) {
+ imageSrcSet = options.imageSrcSet;
+ imageSizes = options.imageSizes;
+ fetchPriority = options.fetchPriority;
+ }
+
+ const key = getImageResourceKey(href, imageSrcSet, imageSizes);
+
+ if (resumableState.imageResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resumableState.imageResources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && fetchPriority === 'high' && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit a preload as a header so we
+ // track this to make sure we don't reset it.
+ renderState.resets.image[key] = PRELOAD_NO_CREDS;
+
+ if (headers.highImagePreloads) {
+ headers.highImagePreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.highImagePreloads += header;
+ } else {
+ // If we don't have headers to write to we have to encode as elements to flush in the head
+ // When we have imageSrcSet the browser probably cannot load the right version from headers
+ // (this should be verified by testing). For now we assume these need to go in the head
+ // as elements even if headers are available.
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ // There is a bug in Safari where imageSrcSet is not respected on preload links
+ // so we omit the href here if we have imageSrcSet b/c safari will load the wrong image.
+ // This harms older browers that do not support imageSrcSet by making their preloads not work
+ // but this population is shrinking fast and is already small so we accept this tradeoff.
+ href: imageSrcSet ? undefined : href,
+ as
+ }, options));
+
+ if (fetchPriority === 'high') {
+ renderState.highImagePreloads.add(resource);
+ } else {
+ renderState.bulkPreloads.add(resource); // Stash the resource in case we need to promote it to higher priority
+ // when an img tag is rendered
+
+ renderState.preloads.images.set(key, resource);
+ }
+ }
+
+ break;
+ }
+
+ case 'style':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.styleResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.styleResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.stylesheets.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ break;
+ }
+
+ case 'script':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.scriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ renderState.preloads.scripts.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.scriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ break;
+ }
+
+ default:
+ {
+ const key = getResourceKey(href);
+ const hasAsType = resumableState.unknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.unknownResources[as] = resources;
+ }
+
+ resources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && as === 'font' && ( // We compute the header here because we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit this preload so we
+ // track it here to prevent it from being reset.
+ renderState.resets.font[key] = PRELOAD_NO_CREDS;
+
+ if (headers.fontPreloads) {
+ headers.fontPreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.fontPreloads += header;
+ } else {
+ // We either don't have headers or we are preloading something that does
+ // not warrant elevated priority so we encode as an element.
+ const resource = [];
+
+ const props = assign({
+ rel: 'preload',
+ href,
+ as
+ }, options);
+
+ pushLinkImpl(resource, props);
+
+ switch (as) {
+ case 'font':
+ renderState.fontPreloads.add(resource);
+ break;
+ // intentional fall through
+
+ default:
+ renderState.bulkPreloads.add(resource);
+ }
+ }
+ }
+ } // If we got this far we created a new resource
+
+
+ flushResources(request);
+ }
+}
+
+function preloadModule(href, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ const key = getResourceKey(href);
+ const as = options && typeof options.as === 'string' ? options.as : 'script';
+ let resource;
+
+ switch (as) {
+ case 'script':
+ {
+ if (resumableState.moduleScriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resource = [];
+ resumableState.moduleScriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.moduleScripts.set(key, resource);
+ break;
+ }
+
+ default:
+ {
+ const hasAsType = resumableState.moduleUnknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.moduleUnknownResources[as] = resources;
+ }
+
+ resource = [];
+ resources[key] = PRELOAD_NO_CREDS;
+ }
+ }
+
+ pushLinkImpl(resource, assign({
+ rel: 'modulepreload',
+ href
+ }, options));
+ renderState.bulkPreloads.add(resource); // If we got this far we created a new resource
+
+ flushResources(request);
+ }
+}
+
+function preinitStyle(href, precedence, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ precedence = precedence || 'default';
+ const key = getResourceKey(href);
+ let styleQueue = renderState.styles.get(precedence);
+ const hasKey = resumableState.styleResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.styleResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.styleResources[key] = EXISTS; // If this is the first time we've encountered this precedence we need
+ // to create a StyleQueue
+
+ if (!styleQueue) {
+ styleQueue = {
+ precedence: stringToChunk(escapeTextForBrowser(precedence)),
+ rules: [],
+ hrefs: [],
+ sheets: new Map()
+ };
+ renderState.styles.set(precedence, styleQueue);
+ }
+
+ const resource = {
+ state: PENDING$1,
+ props: assign({
+ rel: 'stylesheet',
+ href,
+ 'data-precedence': precedence
+ }, options)
+ };
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(resource.props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.stylesheets.get(key);
+
+ if (preloadResource && preloadResource.length > 0) {
+ // The Preload for this resource was created in this render pass and has not flushed yet so
+ // we need to clear it to avoid it flushing.
+ preloadResource.length = 0;
+ } else {
+ // Either the preload resource from this render already flushed in this render pass
+ // or the preload flushed in a prior pass (prerender). In either case we need to mark
+ // this resource as already having been preloaded.
+ resource.state = PRELOADED;
+ }
+ } // We add the newly created resource to our StyleQueue and if necessary
+ // track the resource with the currently rendering boundary
+
+
+ styleQueue.sheets.set(key, resource); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+ }
+}
+
+function preinitScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.scriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.scriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.scriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.scripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+}
+
+function preinitModuleScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.moduleScriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.moduleScriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.moduleScriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ type: 'module',
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.moduleScripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+} // This function is only safe to call at Request start time since it assumes
+// that each module has not already been preloaded. If we find a need to preload
+// scripts at any other point in time we will need to check whether the preload
+// already exists and not assume it
+
+
+function preloadBootstrapScriptOrModule(resumableState, renderState, href, props) {
+
+ const key = getResourceKey(href);
+ // used to preinit the resource. If a script can be preinited then it shouldn't
+ // be a bootstrap script/module and if it is a bootstrap script/module then it
+ // must not be safe to emit early. To avoid possibly allowing for preinits of
+ // bootstrap scripts/modules we occlude these keys.
+
+
+ resumableState.scriptResources[key] = EXISTS;
+ resumableState.moduleScriptResources[key] = EXISTS;
+ const resource = [];
+ pushLinkImpl(resource, props);
+ renderState.bootstrapScripts.add(resource);
+}
+
+function internalPreinitScript(resumableState, renderState, src, chunks) {
+ const key = getResourceKey(src);
+
+ if (!resumableState.scriptResources.hasOwnProperty(key)) {
+ const resource = chunks;
+ resumableState.scriptResources[key] = EXISTS;
+ renderState.scripts.add(resource);
+ }
+
+ return;
+}
+
+function preloadAsStylePropsFromProps(href, props) {
+ return {
+ rel: 'preload',
+ as: 'style',
+ href: href,
+ crossOrigin: props.crossOrigin,
+ fetchPriority: props.fetchPriority,
+ integrity: props.integrity,
+ media: props.media,
+ hrefLang: props.hrefLang,
+ referrerPolicy: props.referrerPolicy
+ };
+}
+
+function stylesheetPropsFromRawProps(rawProps) {
+ return assign({}, rawProps, {
+ 'data-precedence': rawProps.precedence,
+ precedence: null
+ });
+}
+
+function adoptPreloadCredentials(target, preloadState) {
+ if (target.crossOrigin == null) target.crossOrigin = preloadState[0];
+ if (target.integrity == null) target.integrity = preloadState[1];
+}
+
+function getPrefetchDNSAsHeader(href) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ return "<" + escapedHref + ">; rel=dns-prefetch";
+}
+
+function getPreconnectAsHeader(href, crossOrigin) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ let value = "<" + escapedHref + ">; rel=preconnect";
+
+ if (typeof crossOrigin === 'string') {
+ const escapedCrossOrigin = escapeStringForLinkHeaderQuotedParamValueContext(crossOrigin);
+ value += "; crossorigin=\"" + escapedCrossOrigin + "\"";
+ }
+
+ return value;
+}
+
+function getPreloadAsHeader(href, as, params) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ const escapedAs = escapeStringForLinkHeaderQuotedParamValueContext(as);
+ let value = "<" + escapedHref + ">; rel=preload; as=\"" + escapedAs + "\"";
+
+ for (const paramName in params) {
+ if (hasOwnProperty.call(params, paramName)) {
+ const paramValue = params[paramName];
+
+ if (typeof paramValue === 'string') {
+ value += "; " + paramName.toLowerCase() + "=\"" + escapeStringForLinkHeaderQuotedParamValueContext(paramValue) + "\"";
+ }
+ }
+ }
+
+ return value;
+}
+
+function getStylesheetPreloadAsHeader(stylesheet) {
+ const props = stylesheet.props;
+ const preloadOptions = {
+ crossOrigin: props.crossOrigin,
+ integrity: props.integrity,
+ nonce: props.nonce,
+ type: props.type,
+ fetchPriority: props.fetchPriority,
+ referrerPolicy: props.referrerPolicy,
+ media: props.media
+ };
+ return getPreloadAsHeader(props.href, 'style', preloadOptions);
+} // This escaping function is only safe to use for href values being written into
+// a "Link" header in between `<` and `>` characters. The primary concern with the href is
+// to escape the bounding characters as well as new lines. This is unsafe to use in any other
+// context
+
+
+const regexForHrefInLinkHeaderURLContext = /[<>\r\n]/g;
+
+function escapeHrefForLinkHeaderURLContext(hrefInput) {
+
+ const coercedHref = '' + hrefInput;
+ return coercedHref.replace(regexForHrefInLinkHeaderURLContext, escapeHrefForLinkHeaderURLContextReplacer);
+}
+
+function escapeHrefForLinkHeaderURLContextReplacer(match) {
+ switch (match) {
+ case '<':
+ return '%3C';
+
+ case '>':
+ return '%3E';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+} // This escaping function is only safe to use for quoted param values in an HTTP header.
+// It is unsafe to use for any value not inside quote marks in parater value position.
+
+
+const regexForLinkHeaderQuotedParamValueContext = /["';,\r\n]/g;
+
+function escapeStringForLinkHeaderQuotedParamValueContext(value, name) {
+
+ const coerced = '' + value;
+ return coerced.replace(regexForLinkHeaderQuotedParamValueContext, escapeStringForLinkHeaderQuotedParamValueContextReplacer);
+}
+
+function escapeStringForLinkHeaderQuotedParamValueContextReplacer(match) {
+ switch (match) {
+ case '"':
+ return '%22';
+
+ case "'":
+ return '%27';
+
+ case ';':
+ return '%3B';
+
+ case ',':
+ return '%2C';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+}
+
+function hoistStyleQueueDependency(styleQueue) {
+ this.styles.add(styleQueue);
+}
+
+function hoistStylesheetDependency(stylesheet) {
+ this.stylesheets.add(stylesheet);
+}
+
+function hoistResources(renderState, source) {
+ const currentBoundaryResources = renderState.boundaryResources;
+
+ if (currentBoundaryResources) {
+ source.styles.forEach(hoistStyleQueueDependency, currentBoundaryResources);
+ source.stylesheets.forEach(hoistStylesheetDependency, currentBoundaryResources);
+ }
+} // This function is called at various times depending on whether we are rendering
+// or prerendering. In this implementation we only actually emit headers once and
+// subsequent calls are ignored. We track whether the request has a completed shell
+// to determine whether we will follow headers with a flush including stylesheets.
+// In the context of prerrender we don't have a completed shell when the request finishes
+// with a postpone in the shell. In the context of a render we don't have a completed shell
+// if this is called before the shell finishes rendering which usually will happen anytime
+// anything suspends in the shell.
+
+function emitEarlyPreloads(renderState, resumableState, shellComplete) {
+ const onHeaders = renderState.onHeaders;
+
+ if (onHeaders) {
+ const headers = renderState.headers;
+
+ if (headers) {
+ let linkHeader = headers.preconnects;
+
+ if (headers.fontPreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.fontPreloads;
+ }
+
+ if (headers.highImagePreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.highImagePreloads;
+ }
+
+ if (!shellComplete) {
+ // We use raw iterators because we want to be able to halt iteration
+ // We could refactor renderState to store these dually in arrays to
+ // make this more efficient at the cost of additional memory and
+ // write overhead. However this code only runs once per request so
+ // for now I consider this sufficient.
+ const queueIter = renderState.styles.values();
+
+ outer: for (let queueStep = queueIter.next(); headers.remainingCapacity > 0 && !queueStep.done; queueStep = queueIter.next()) {
+ const sheets = queueStep.value.sheets;
+ const sheetIter = sheets.values();
+
+ for (let sheetStep = sheetIter.next(); headers.remainingCapacity > 0 && !sheetStep.done; sheetStep = sheetIter.next()) {
+ const sheet = sheetStep.value;
+ const props = sheet.props;
+ const key = getResourceKey(props.href);
+ const header = getStylesheetPreloadAsHeader(sheet); // We mutate the capacity b/c we don't want to keep checking if later headers will fit.
+ // This means that a particularly long header might close out the header queue where later
+ // headers could still fit. We could in the future alter the behavior here based on prerender vs render
+ // since during prerender we aren't as concerned with pure runtime performance.
+
+ if ((headers.remainingCapacity -= header.length) >= 2) {
+ renderState.resets.style[key] = PRELOAD_NO_CREDS;
+
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += header; // We already track that the resource exists in resumableState however
+ // if the resumableState resets because we postponed in the shell
+ // which is what is happening in this branch if we are prerendering
+ // then we will end up resetting the resumableState. When it resets we
+ // want to record the fact that this stylesheet was already preloaded
+
+ renderState.resets.style[key] = typeof props.crossOrigin === 'string' || typeof props.integrity === 'string' ? [props.crossOrigin, props.integrity] : PRELOAD_NO_CREDS;
+ } else {
+ break outer;
+ }
+ }
+ }
+ }
+
+ if (linkHeader) {
+ onHeaders({
+ Link: linkHeader
+ });
+ } else {
+ // We still call this with no headers because a user may be using it as a signal that
+ // it React will not provide any headers
+ onHeaders({});
+ }
+
+ renderState.headers = null;
+ return;
+ }
+ }
+}
+const NotPendingTransition = NotPending;
+
+// ATTENTION
+// When adding new symbols to this file,
+// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
+// The Symbol used to tag the ReactElement-like types.
+const REACT_ELEMENT_TYPE = Symbol.for('react.element');
+const REACT_PORTAL_TYPE = Symbol.for('react.portal');
+const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
+const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
+const REACT_PROFILER_TYPE = Symbol.for('react.profiler');
+const REACT_PROVIDER_TYPE = Symbol.for('react.provider');
+const REACT_CONTEXT_TYPE = Symbol.for('react.context');
+const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
+const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
+const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
+const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
+const REACT_MEMO_TYPE = Symbol.for('react.memo');
+const REACT_LAZY_TYPE = Symbol.for('react.lazy');
+const REACT_SCOPE_TYPE = Symbol.for('react.scope');
+const REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');
+const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
+const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');
+const REACT_CACHE_TYPE = Symbol.for('react.cache');
+const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value');
+const REACT_MEMO_CACHE_SENTINEL = Symbol.for('react.memo_cache_sentinel');
+const REACT_POSTPONE_TYPE = Symbol.for('react.postpone');
+const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
+const FAUX_ITERATOR_SYMBOL = '@@iterator';
+function getIteratorFn(maybeIterable) {
+ if (maybeIterable === null || typeof maybeIterable !== 'object') {
+ return null;
+ }
+
+ const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
+
+ if (typeof maybeIterator === 'function') {
+ return maybeIterator;
+ }
+
+ return null;
+}
+
+function getWrappedName(outerType, innerType, wrapperName) {
+ const displayName = outerType.displayName;
+
+ if (displayName) {
+ return displayName;
+ }
+
+ const functionName = innerType.displayName || innerType.name || '';
+ return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName;
+} // Keep in sync with react-reconciler/getComponentNameFromFiber
+
+
+function getContextName(type) {
+ return type.displayName || 'Context';
+} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+
+
+function getComponentNameFromType(type) {
+ if (type == null) {
+ // Host root, text node or just invalid type.
+ return null;
+ }
+
+ if (typeof type === 'function') {
+ return type.displayName || type.name || null;
+ }
+
+ if (typeof type === 'string') {
+ return type;
+ }
+
+ switch (type) {
+ case REACT_FRAGMENT_TYPE:
+ return 'Fragment';
+
+ case REACT_PORTAL_TYPE:
+ return 'Portal';
+
+ case REACT_PROFILER_TYPE:
+ return 'Profiler';
+
+ case REACT_STRICT_MODE_TYPE:
+ return 'StrictMode';
+
+ case REACT_SUSPENSE_TYPE:
+ return 'Suspense';
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ return 'SuspenseList';
+
+ case REACT_CACHE_TYPE:
+ {
+ return 'Cache';
+ }
+
+ }
+
+ if (typeof type === 'object') {
+ switch (type.$$typeof) {
+ case REACT_CONTEXT_TYPE:
+ const context = type;
+ return getContextName(context) + '.Consumer';
+
+ case REACT_PROVIDER_TYPE:
+ const provider = type;
+ return getContextName(provider._context) + '.Provider';
+
+ case REACT_FORWARD_REF_TYPE:
+ return getWrappedName(type, type.render, 'ForwardRef');
+
+ case REACT_MEMO_TYPE:
+ const outerName = type.displayName || null;
+
+ if (outerName !== null) {
+ return outerName;
+ }
+
+ return getComponentNameFromType(type.type) || 'Memo';
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyComponent = type;
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+
+ try {
+ return getComponentNameFromType(init(payload));
+ } catch (x) {
+ return null;
+ }
+ }
+
+ case REACT_SERVER_CONTEXT_TYPE:
+ {
+ const context2 = type;
+ return (context2.displayName || context2._globalName) + '.Provider';
+ }
+
+ }
+ }
+
+ return null;
+}
+
+const emptyContextObject = {};
+
+function getMaskedContext(type, unmaskedContext) {
+ {
+ const contextTypes = type.contextTypes;
+
+ if (!contextTypes) {
+ return emptyContextObject;
+ }
+
+ const context = {};
+
+ for (const key in contextTypes) {
+ context[key] = unmaskedContext[key];
+ }
+
+ return context;
+ }
+}
+function processChildContext(instance, type, parentContext, childContextTypes) {
+ {
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
+ if (typeof instance.getChildContext !== 'function') {
+
+ return parentContext;
+ }
+
+ const childContext = instance.getChildContext();
+
+ for (const contextKey in childContext) {
+ if (!(contextKey in childContextTypes)) {
+ throw new Error((getComponentNameFromType(type) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes.");
+ }
+ }
+
+ return assign({}, parentContext, childContext);
+ }
+}
+
+// Forming a reverse tree.
+// The structure of a context snapshot is an implementation of this file.
+// Currently, it's implemented as tracking the current active node.
+
+
+const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
+// This global (actually thread local) state represents what state all those "current",
+// fields are currently in.
+
+let currentActiveSnapshot = null;
+
+function popNode(prev) {
+ {
+ prev.context._currentValue = prev.parentValue;
+ }
+}
+
+function pushNode(next) {
+ {
+ next.context._currentValue = next.value;
+ }
+}
+
+function popToNearestCommonAncestor(prev, next) {
+ if (prev === next) ; else {
+ popNode(prev);
+ const parentPrev = prev.parent;
+ const parentNext = next.parent;
+
+ if (parentPrev === null) {
+ if (parentNext !== null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+ } else {
+ if (parentNext === null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+
+ popToNearestCommonAncestor(parentPrev, parentNext);
+ } // On the way back, we push the new ones that weren't common.
+
+
+ pushNode(next);
+ }
+}
+
+function popAllPrevious(prev) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev !== null) {
+ popAllPrevious(parentPrev);
+ }
+}
+
+function pushAllNext(next) {
+ const parentNext = next.parent;
+
+ if (parentNext !== null) {
+ pushAllNext(parentNext);
+ }
+
+ pushNode(next);
+}
+
+function popPreviousToCommonLevel(prev, next) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (parentPrev.depth === next.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(parentPrev, next);
+ } else {
+ // We must still be deeper.
+ popPreviousToCommonLevel(parentPrev, next);
+ }
+}
+
+function popNextToCommonLevel(prev, next) {
+ const parentNext = next.parent;
+
+ if (parentNext === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (prev.depth === parentNext.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(prev, parentNext);
+ } else {
+ // We must still be deeper.
+ popNextToCommonLevel(prev, parentNext);
+ }
+
+ pushNode(next);
+} // Perform context switching to the new snapshot.
+// To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
+// updating all the context's current values. That way reads, always just read the current value.
+// At the cost of updating contexts even if they're never read by this subtree.
+
+
+function switchContext(newSnapshot) {
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
+ // We also need to update any new contexts that are now on the stack with the deepest value.
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
+ // for that. Therefore this algorithm is recursive.
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
+ // 3) Then we reapply new contexts on the way back up the stack.
+ const prev = currentActiveSnapshot;
+ const next = newSnapshot;
+
+ if (prev !== next) {
+ if (prev === null) {
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
+ pushAllNext(next);
+ } else if (next === null) {
+ popAllPrevious(prev);
+ } else if (prev.depth === next.depth) {
+ popToNearestCommonAncestor(prev, next);
+ } else if (prev.depth > next.depth) {
+ popPreviousToCommonLevel(prev, next);
+ } else {
+ popNextToCommonLevel(prev, next);
+ }
+
+ currentActiveSnapshot = next;
+ }
+}
+function pushProvider(context, nextValue) {
+ let prevValue;
+
+ {
+ prevValue = context._currentValue;
+ context._currentValue = nextValue;
+ }
+
+ const prevNode = currentActiveSnapshot;
+ const newNode = {
+ parent: prevNode,
+ depth: prevNode === null ? 0 : prevNode.depth + 1,
+ context: context,
+ parentValue: prevValue,
+ value: nextValue
+ };
+ currentActiveSnapshot = newNode;
+ return newNode;
+}
+function popProvider(context) {
+ const prevSnapshot = currentActiveSnapshot;
+
+ if (prevSnapshot === null) {
+ throw new Error('Tried to pop a Context at the root of the app. This is a bug in React.');
+ }
+
+ {
+ const value = prevSnapshot.parentValue;
+
+ if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) {
+ prevSnapshot.context._currentValue = prevSnapshot.context._defaultValue;
+ } else {
+ prevSnapshot.context._currentValue = value;
+ }
+ }
+
+ return currentActiveSnapshot = prevSnapshot.parent;
+}
+function getActiveContext() {
+ return currentActiveSnapshot;
+}
+function readContext$1(context) {
+ const value = context._currentValue ;
+ return value;
+}
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ *
+ * Note that this module is currently shared and assumed to be stateless.
+ * If this becomes an actual Map, that will break.
+ */
+function get(key) {
+ return key._reactInternals;
+}
+function set(key, value) {
+ key._reactInternals = value;
+}
+
+const classComponentUpdater = {
+ isMounted(inst) {
+ return false;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueSetState(inst, payload, callback) {
+ const internals = get(inst);
+
+ if (internals.queue === null) ; else {
+ internals.queue.push(payload);
+ }
+ },
+
+ enqueueReplaceState(inst, payload, callback) {
+ const internals = get(inst);
+ internals.replace = true;
+ internals.queue = [payload];
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueForceUpdate(inst, callback) {
+ }
+
+};
+
+function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) {
+ const partialState = getDerivedStateFromProps(nextProps, prevState);
+
+
+ const newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);
+ return newState;
+}
+
+function constructClassInstance(ctor, props, maskedLegacyContext) {
+ let context = emptyContextObject;
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ context = readContext$1(contextType);
+ } else {
+ context = maskedLegacyContext;
+ }
+
+ const instance = new ctor(props, context);
+
+ return instance;
+}
+
+function callComponentWillMount(type, instance) {
+ const oldState = instance.state;
+
+ if (typeof instance.componentWillMount === 'function') {
+
+ instance.componentWillMount();
+ }
+
+ if (typeof instance.UNSAFE_componentWillMount === 'function') {
+ instance.UNSAFE_componentWillMount();
+ }
+
+ if (oldState !== instance.state) {
+
+ classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
+ }
+}
+
+function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) {
+ if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
+ const oldQueue = internalInstance.queue;
+ const oldReplace = internalInstance.replace;
+ internalInstance.queue = null;
+ internalInstance.replace = false;
+
+ if (oldReplace && oldQueue.length === 1) {
+ inst.state = oldQueue[0];
+ } else {
+ let nextState = oldReplace ? oldQueue[0] : inst.state;
+ let dontMutate = true;
+
+ for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
+ const partial = oldQueue[i];
+ const partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial;
+
+ if (partialState != null) {
+ if (dontMutate) {
+ dontMutate = false;
+ nextState = assign({}, nextState, partialState);
+ } else {
+ assign(nextState, partialState);
+ }
+ }
+ }
+
+ inst.state = nextState;
+ }
+ } else {
+ internalInstance.queue = null;
+ }
+} // Invokes the mount life-cycles on a previously never rendered instance.
+
+
+function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) {
+
+ const initialState = instance.state !== undefined ? instance.state : null;
+ instance.updater = classComponentUpdater;
+ instance.props = newProps;
+ instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway.
+ // The internal instance will be used to manage updates that happen during this mount.
+
+ const internalInstance = {
+ queue: [],
+ replace: false
+ };
+ set(instance, internalInstance);
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ instance.context = readContext$1(contextType);
+ } else {
+ instance.context = maskedLegacyContext;
+ }
+
+ const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
+
+ if (typeof getDerivedStateFromProps === 'function') {
+ instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps);
+ } // In order to support react-lifecycles-compat polyfilled components,
+ // Unsafe lifecycles should not be invoked for components using the new APIs.
+
+
+ if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
+ callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's
+ // process them now.
+
+ processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext);
+ }
+}
+
+// Ids are base 32 strings whose binary representation corresponds to the
+// position of a node in a tree.
+// Every time the tree forks into multiple children, we add additional bits to
+// the left of the sequence that represent the position of the child within the
+// current level of children.
+//
+// 00101 00010001011010101
+// ╰─┬─╯ ╰───────┬───────╯
+// Fork 5 of 20 Parent id
+//
+// The leading 0s are important. In the above example, you only need 3 bits to
+// represent slot 5. However, you need 5 bits to represent all the forks at
+// the current level, so we must account for the empty bits at the end.
+//
+// For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise,
+// the zeroth id at a level would be indistinguishable from its parent.
+//
+// If a node has only one child, and does not materialize an id (i.e. does not
+// contain a useId hook), then we don't need to allocate any space in the
+// sequence. It's treated as a transparent indirection. For example, these two
+// trees produce the same ids:
+//
+// <> <>
+//
+//
+// >
+//
+// >
+//
+// However, we cannot skip any node that materializes an id. Otherwise, a parent
+// id that does not fork would be indistinguishable from its child id. For
+// example, this tree does not fork, but the parent and child must have
+// different ids.
+//
+//
+//
+//
+//
+// To handle this scenario, every time we materialize an id, we allocate a
+// new level with a single slot. You can think of this as a fork with only one
+// prong, or an array of children with length 1.
+//
+// It's possible for the size of the sequence to exceed 32 bits, the max
+// size for bitwise operations. When this happens, we make more room by
+// converting the right part of the id to a string and storing it in an overflow
+// variable. We use a base 32 string representation, because 32 is the largest
+// power of 2 that is supported by toString(). We want the base to be large so
+// that the resulting ids are compact, and we want the base to be a power of 2
+// because every log2(base) bits corresponds to a single character, i.e. every
+// log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without
+// affecting the final result.
+const emptyTreeContext = {
+ id: 1,
+ overflow: ''
+};
+function getTreeId(context) {
+ const overflow = context.overflow;
+ const idWithLeadingBit = context.id;
+ const id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);
+ return id.toString(32) + overflow;
+}
+function pushTreeContext(baseContext, totalChildren, index) {
+ const baseIdWithLeadingBit = baseContext.id;
+ const baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part
+ // of the id; we use it to account for leading 0s.
+
+ const baseLength = getBitLength(baseIdWithLeadingBit) - 1;
+ const baseId = baseIdWithLeadingBit & ~(1 << baseLength);
+ const slot = index + 1;
+ const length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into
+ // consideration the leading 1 we use to mark the end of the sequence.
+
+ if (length > 30) {
+ // We overflowed the bitwise-safe range. Fall back to slower algorithm.
+ // This branch assumes the length of the base id is greater than 5; it won't
+ // work for smaller ids, because you need 5 bits per character.
+ //
+ // We encode the id in multiple steps: first the base id, then the
+ // remaining digits.
+ //
+ // Each 5 bit sequence corresponds to a single base 32 character. So for
+ // example, if the current id is 23 bits long, we can convert 20 of those
+ // bits into a string of 4 characters, with 3 bits left over.
+ //
+ // First calculate how many bits in the base id represent a complete
+ // sequence of characters.
+ const numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.
+
+ const newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.
+
+ const newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.
+
+ const restOfBaseId = baseId >> numberOfOverflowBits;
+ const restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because
+ // we made more room, this time it won't overflow.
+
+ const restOfLength = getBitLength(totalChildren) + restOfBaseLength;
+ const restOfNewBits = slot << restOfBaseLength;
+ const id = restOfNewBits | restOfBaseId;
+ const overflow = newOverflow + baseOverflow;
+ return {
+ id: 1 << restOfLength | id,
+ overflow
+ };
+ } else {
+ // Normal path
+ const newBits = slot << baseLength;
+ const id = newBits | baseId;
+ const overflow = baseOverflow;
+ return {
+ id: 1 << length | id,
+ overflow
+ };
+ }
+}
+
+function getBitLength(number) {
+ return 32 - clz32(number);
+}
+
+function getLeadingBit(id) {
+ return 1 << getBitLength(id) - 1;
+} // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback.
+
+
+const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.
+// Based on:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+const log = Math.log;
+const LN2 = Math.LN2;
+
+function clz32Fallback(x) {
+ const asUint = x >>> 0;
+
+ if (asUint === 0) {
+ return 32;
+ }
+
+ return 31 - (log(asUint) / LN2 | 0) | 0;
+}
+
+// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
+// changes to one module should be reflected in the others.
+// TODO: Rename this module and the corresponding Fiber one to "Thenable"
+// instead of "Wakeable". Or some other more appropriate name.
+// An error that is thrown (e.g. by `use`) to trigger Suspense. If we
+// detect this is caught by userspace, we'll log a warning in development.
+const SuspenseException = new Error("Suspense Exception: This is not a real error! It's an implementation " + 'detail of `use` to interrupt the current render. You must either ' + 'rethrow it immediately, or move the `use` call outside of the ' + '`try/catch` block. Capturing without rethrowing will lead to ' + 'unexpected behavior.\n\n' + 'To handle async errors, wrap your component in an error boundary, or ' + "call the promise's `.catch` method and pass the result to `use`");
+function createThenableState() {
+ // The ThenableState is created the first time a component suspends. If it
+ // suspends again, we'll reuse the same state.
+ return [];
+}
+
+function noop$2() {}
+
+function trackUsedThenable(thenableState, thenable, index) {
+ const previous = thenableState[index];
+
+ if (previous === undefined) {
+ thenableState.push(thenable);
+ } else {
+ if (previous !== thenable) {
+ // Reuse the previous thenable, and drop the new one. We can assume
+ // they represent the same value, because components are idempotent.
+ // Avoid an unhandled rejection errors for the Promises that we'll
+ // intentionally ignore.
+ thenable.then(noop$2, noop$2);
+ thenable = previous;
+ }
+ } // We use an expando to track the status and result of a thenable so that we
+ // can synchronously unwrap the value. Think of this as an extension of the
+ // Promise API, or a custom interface that is a superset of Thenable.
+ //
+ // If the thenable doesn't have a status, set it to "pending" and attach
+ // a listener that will update its status and result when it resolves.
+
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledValue = thenable.value;
+ return fulfilledValue;
+ }
+
+ case 'rejected':
+ {
+ const rejectedError = thenable.reason;
+ throw rejectedError;
+ }
+
+ default:
+ {
+ if (typeof thenable.status === 'string') ; else {
+ const pendingThenable = thenable;
+ pendingThenable.status = 'pending';
+ pendingThenable.then(fulfilledValue => {
+ if (thenable.status === 'pending') {
+ const fulfilledThenable = thenable;
+ fulfilledThenable.status = 'fulfilled';
+ fulfilledThenable.value = fulfilledValue;
+ }
+ }, error => {
+ if (thenable.status === 'pending') {
+ const rejectedThenable = thenable;
+ rejectedThenable.status = 'rejected';
+ rejectedThenable.reason = error;
+ }
+ }); // Check one more time in case the thenable resolved synchronously
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledThenable = thenable;
+ return fulfilledThenable.value;
+ }
+
+ case 'rejected':
+ {
+ const rejectedThenable = thenable;
+ throw rejectedThenable.reason;
+ }
+ }
+ } // Suspend.
+ //
+ // Throwing here is an implementation detail that allows us to unwind the
+ // call stack. But we shouldn't allow it to leak into userspace. Throw an
+ // opaque placeholder value instead of the actual thenable. If it doesn't
+ // get captured by the work loop, log a warning, because that means
+ // something in userspace must have caught it.
+
+
+ suspendedThenable = thenable;
+ throw SuspenseException;
+ }
+ }
+} // This is used to track the actual thenable that suspended so it can be
+// passed to the rest of the Suspense implementation — which, for historical
+// reasons, expects to receive a thenable.
+
+let suspendedThenable = null;
+function getSuspendedThenable() {
+ // This is called right after `use` suspends by throwing an exception. `use`
+ // throws an opaque value instead of the thenable itself so that it can't be
+ // caught in userspace. Then the work loop accesses the actual thenable using
+ // this function.
+ if (suspendedThenable === null) {
+ throw new Error('Expected a suspended thenable. This is a bug in React. Please file ' + 'an issue.');
+ }
+
+ const thenable = suspendedThenable;
+ suspendedThenable = null;
+ return thenable;
+}
+
+/**
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+ */
+function is(x, y) {
+ return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
+ ;
+}
+
+const objectIs = // $FlowFixMe[method-unbinding]
+typeof Object.is === 'function' ? Object.is : is;
+
+let currentlyRenderingComponent = null;
+let currentlyRenderingTask = null;
+let currentlyRenderingRequest = null;
+let currentlyRenderingKeyPath = null;
+let firstWorkInProgressHook = null;
+let workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook
+
+let isReRender = false; // Whether an update was scheduled during the currently executing render pass.
+
+let didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component
+
+let localIdCounter = 0; // Chunks that should be pushed to the stream once the component
+// finishes rendering.
+// Counts the number of useFormState calls in this component
+
+let formStateCounter = 0; // The index of the useFormState hook that matches the one passed in at the
+// root during an MPA navigation, if any.
+
+let formStateMatchingIndex = -1; // Counts the number of use(thenable) calls in this component
+
+let thenableIndexCounter = 0;
+let thenableState = null; // Lazily created map of render-phase updates
+
+let renderPhaseUpdates = null; // Counter to prevent infinite loops.
+
+let numberOfReRenders = 0;
+const RE_RENDER_LIMIT = 25;
+
+function resolveCurrentlyRenderingComponent() {
+ if (currentlyRenderingComponent === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + '2. You might be breaking the Rules of Hooks\n' + '3. You might have more than one copy of React in the same app\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.');
+ }
+
+ return currentlyRenderingComponent;
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+
+ return false;
+ }
+
+
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ if (objectIs(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+function createHook() {
+ if (numberOfReRenders > 0) {
+ throw new Error('Rendered more hooks than during the previous render');
+ }
+
+ return {
+ memoizedState: null,
+ queue: null,
+ next: null
+ };
+}
+
+function createWorkInProgressHook() {
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ if (firstWorkInProgressHook === null) {
+ isReRender = false;
+ firstWorkInProgressHook = workInProgressHook = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = firstWorkInProgressHook;
+ }
+ } else {
+ if (workInProgressHook.next === null) {
+ isReRender = false; // Append to the end of the list
+
+ workInProgressHook = workInProgressHook.next = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = workInProgressHook.next;
+ }
+ }
+
+ return workInProgressHook;
+}
+
+function prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState) {
+ currentlyRenderingComponent = componentIdentity;
+ currentlyRenderingTask = task;
+ currentlyRenderingRequest = request;
+ currentlyRenderingKeyPath = keyPath;
+ // didScheduleRenderPhaseUpdate = false;
+ // firstWorkInProgressHook = null;
+ // numberOfReRenders = 0;
+ // renderPhaseUpdates = null;
+ // workInProgressHook = null;
+
+
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ thenableState = prevThenableState;
+}
+function finishHooks(Component, props, children, refOrContext) {
+ // This must be called after every function component to prevent hooks from
+ // being used in classes.
+ while (didScheduleRenderPhaseUpdate) {
+ // Updates were scheduled during the render phase. They are stored in
+ // the `renderPhaseUpdates` map. Call the component again, reusing the
+ // work-in-progress hooks and applying the additional updates on top. Keep
+ // restarting until no more updates are scheduled.
+ didScheduleRenderPhaseUpdate = false;
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ numberOfReRenders += 1; // Start over from the beginning of the list
+
+ workInProgressHook = null;
+ children = Component(props, refOrContext);
+ }
+
+ resetHooksState();
+ return children;
+}
+function getThenableStateAfterSuspending() {
+ const state = thenableState;
+ thenableState = null;
+ return state;
+}
+function checkDidRenderIdHook() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ const didRenderIdHook = localIdCounter !== 0;
+ return didRenderIdHook;
+}
+function getFormStateCount() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateCounter;
+}
+function getFormStateMatchingIndex() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateMatchingIndex;
+} // Reset the internal hooks state if an error occurs while rendering a component
+
+function resetHooksState() {
+
+ currentlyRenderingComponent = null;
+ currentlyRenderingTask = null;
+ currentlyRenderingRequest = null;
+ currentlyRenderingKeyPath = null;
+ didScheduleRenderPhaseUpdate = false;
+ firstWorkInProgressHook = null;
+ numberOfReRenders = 0;
+ renderPhaseUpdates = null;
+ workInProgressHook = null;
+}
+
+function readContext(context) {
+
+ return readContext$1(context);
+}
+
+function useContext(context) {
+
+ resolveCurrentlyRenderingComponent();
+ return readContext$1(context);
+}
+
+function basicStateReducer(state, action) {
+ // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
+ return typeof action === 'function' ? action(state) : action;
+}
+
+function useState(initialState) {
+
+ return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers
+ initialState);
+}
+function useReducer(reducer, initialArg, init) {
+
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+
+ if (isReRender) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ // current hook.
+ const queue = workInProgressHook.queue;
+ const dispatch = queue.dispatch;
+
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate !== undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.delete(queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ let newState = workInProgressHook.memoizedState;
+ let update = firstRenderPhaseUpdate;
+
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ const action = update.action;
+
+ newState = reducer(newState, action);
+
+
+ update = update.next;
+ } while (update !== null); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ workInProgressHook.memoizedState = newState;
+ return [newState, dispatch];
+ }
+ } // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ return [workInProgressHook.memoizedState, dispatch];
+ } else {
+
+ let initialState;
+
+ if (reducer === basicStateReducer) {
+ // Special case for `useState`.
+ initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
+ } else {
+ initialState = init !== undefined ? init(initialArg) : initialArg;
+ }
+
+
+ workInProgressHook.memoizedState = initialState; // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ const queue = workInProgressHook.queue = {
+ last: null,
+ dispatch: null
+ };
+ const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ return [workInProgressHook.memoizedState, dispatch];
+ }
+}
+
+function useMemo(nextCreate, deps) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const nextDeps = deps === undefined ? null : deps;
+
+ if (workInProgressHook !== null) {
+ const prevState = workInProgressHook.memoizedState;
+
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ const prevDeps = prevState[1];
+
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ }
+
+ const nextValue = nextCreate();
+
+
+ workInProgressHook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function useRef(initialValue) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const previousRef = workInProgressHook.memoizedState;
+
+ if (previousRef === null) {
+ const ref = {
+ current: initialValue
+ };
+
+
+ workInProgressHook.memoizedState = ref;
+ return ref;
+ } else {
+ return previousRef;
+ }
+}
+
+function dispatchAction(componentIdentity, queue, action) {
+ if (numberOfReRenders >= RE_RENDER_LIMIT) {
+ throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.');
+ }
+
+ if (componentIdentity === currentlyRenderingComponent) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ const update = {
+ action,
+ next: null
+ };
+
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate === undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+
+ lastRenderPhaseUpdate.next = update;
+ }
+ }
+}
+
+function useCallback(callback, deps) {
+ return useMemo(() => callback, deps);
+}
+
+function throwOnUseEffectEventCall() {
+ throw new Error("A function wrapped in useEffectEvent can't be called during rendering.");
+}
+
+function useEffectEvent(callback) {
+ // $FlowIgnore[incompatible-return]
+ return throwOnUseEffectEventCall;
+}
+
+function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
+ if (getServerSnapshot === undefined) {
+ throw new Error('Missing getServerSnapshot, which is required for ' + 'server-rendered content. Will revert to client rendering.');
+ }
+
+ return getServerSnapshot();
+}
+
+function useDeferredValue(value, initialValue) {
+ resolveCurrentlyRenderingComponent();
+
+ {
+ return initialValue !== undefined ? initialValue : value;
+ }
+}
+
+function unsupportedStartTransition() {
+ throw new Error('startTransition cannot be called during server rendering.');
+}
+
+function useTransition() {
+ resolveCurrentlyRenderingComponent();
+ return [false, unsupportedStartTransition];
+}
+
+function useHostTransitionStatus() {
+ resolveCurrentlyRenderingComponent();
+ return NotPendingTransition;
+}
+
+function unsupportedSetOptimisticState() {
+ throw new Error('Cannot update optimistic state while rendering.');
+}
+
+function useOptimistic(passthrough, reducer) {
+ resolveCurrentlyRenderingComponent();
+ return [passthrough, unsupportedSetOptimisticState];
+}
+
+function createPostbackFormStateKey(permalink, componentKeyPath, hookIndex) {
+ if (permalink !== undefined) {
+ // Don't bother to hash a permalink-based key since it's already short.
+ return 'p' + permalink;
+ } else {
+ // Append a node to the key path that represents the form state hook.
+ const keyPath = [componentKeyPath, null, hookIndex]; // Key paths are hashed to reduce the size. It does not need to be secure,
+ // and it's more important that it's fast than that it's completely
+ // collision-free.
+
+ const keyPathHash = createFastHash(JSON.stringify(keyPath));
+ return 'k' + keyPathHash;
+ }
+}
+
+function useFormState(action, initialState, permalink) {
+ resolveCurrentlyRenderingComponent(); // Count the number of useFormState hooks per component. We also use this to
+ // track the position of this useFormState hook relative to the other ones in
+ // this component, so we can generate a unique key for each one.
+
+ const formStateHookIndex = formStateCounter++;
+ const request = currentlyRenderingRequest; // $FlowIgnore[prop-missing]
+
+ const formAction = action.$$FORM_ACTION;
+
+ if (typeof formAction === 'function') {
+ // This is a server action. These have additional features to enable
+ // MPA-style form submissions with progressive enhancement.
+ // TODO: If the same permalink is passed to multiple useFormStates, and
+ // they all have the same action signature, Fizz will pass the postback
+ // state to all of them. We should probably only pass it to the first one,
+ // and/or warn.
+ // The key is lazily generated and deduped so the that the keypath doesn't
+ // get JSON.stringify-ed unnecessarily, and at most once.
+ let nextPostbackStateKey = null; // Determine the current form state. If we received state during an MPA form
+ // submission, then we will reuse that, if the action identity matches.
+ // Otherwise we'll use the initial state argument. We will emit a comment
+ // marker into the stream that indicates whether the state was reused.
+
+ let state = initialState;
+ const componentKeyPath = currentlyRenderingKeyPath;
+ const postbackFormState = getFormState(request); // $FlowIgnore[prop-missing]
+
+ const isSignatureEqual = action.$$IS_SIGNATURE_EQUAL;
+
+ if (postbackFormState !== null && typeof isSignatureEqual === 'function') {
+ const postbackKey = postbackFormState[1];
+ const postbackReferenceId = postbackFormState[2];
+ const postbackBoundArity = postbackFormState[3];
+
+ if (isSignatureEqual.call(action, postbackReferenceId, postbackBoundArity)) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+
+ if (postbackKey === nextPostbackStateKey) {
+ // This was a match
+ formStateMatchingIndex = formStateHookIndex; // Reuse the state that was submitted by the form.
+
+ state = postbackFormState[0];
+ }
+ }
+ } // Bind the state to the first argument of the action.
+
+
+ const boundAction = action.bind(null, state); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ }; // $FlowIgnore[prop-missing]
+
+
+ if (typeof boundAction.$$FORM_ACTION === 'function') {
+ // $FlowIgnore[prop-missing]
+ dispatch.$$FORM_ACTION = prefix => {
+ const metadata = boundAction.$$FORM_ACTION(prefix); // Override the action URL
+
+ if (permalink !== undefined) {
+
+ permalink += '';
+ metadata.action = permalink;
+ }
+
+ const formData = metadata.data;
+
+ if (formData) {
+ if (nextPostbackStateKey === null) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+ }
+
+ formData.append('$ACTION_KEY', nextPostbackStateKey);
+ }
+
+ return metadata;
+ };
+ }
+
+ return [state, dispatch];
+ } else {
+ // This is not a server action, so the implementation is much simpler.
+ // Bind the state to the first argument of the action.
+ const boundAction = action.bind(null, initialState); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ };
+
+ return [initialState, dispatch];
+ }
+}
+
+function useId() {
+ const task = currentlyRenderingTask;
+ const treeId = getTreeId(task.treeContext);
+ const resumableState = currentResumableState;
+
+ if (resumableState === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component.');
+ }
+
+ const localId = localIdCounter++;
+ return makeId(resumableState, treeId, localId);
+}
+
+function use(usable) {
+ if (usable !== null && typeof usable === 'object') {
+ // $FlowFixMe[method-unbinding]
+ if (typeof usable.then === 'function') {
+ // This is a thenable.
+ const thenable = usable;
+ return unwrapThenable(thenable);
+ } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = usable;
+ return readContext(context);
+ }
+ } // eslint-disable-next-line react-internal/safe-string-coercion
+
+
+ throw new Error('An unsupported type was passed to use(): ' + String(usable));
+}
+
+function unwrapThenable(thenable) {
+ const index = thenableIndexCounter;
+ thenableIndexCounter += 1;
+
+ if (thenableState === null) {
+ thenableState = createThenableState();
+ }
+
+ return trackUsedThenable(thenableState, thenable, index);
+}
+
+function unsupportedRefresh() {
+ throw new Error('Cache cannot be refreshed during server rendering.');
+}
+
+function useCacheRefresh() {
+ return unsupportedRefresh;
+}
+
+function useMemoCache(size) {
+ const data = new Array(size);
+
+ for (let i = 0; i < size; i++) {
+ data[i] = REACT_MEMO_CACHE_SENTINEL;
+ }
+
+ return data;
+}
+
+function noop$1() {}
+
+const HooksDispatcher = {
+ readContext,
+ use,
+ useContext,
+ useMemo,
+ useReducer,
+ useRef,
+ useState,
+ useInsertionEffect: noop$1,
+ useLayoutEffect: noop$1,
+ useCallback,
+ // useImperativeHandle is not run in the server environment
+ useImperativeHandle: noop$1,
+ // Effects are not run in the server environment.
+ useEffect: noop$1,
+ // Debugging effect
+ useDebugValue: noop$1,
+ useDeferredValue,
+ useTransition,
+ useId,
+ // Subscriptions are not setup in a server environment.
+ useSyncExternalStore
+};
+
+{
+ HooksDispatcher.useCacheRefresh = useCacheRefresh;
+}
+
+{
+ HooksDispatcher.useEffectEvent = useEffectEvent;
+}
+
+{
+ HooksDispatcher.useMemoCache = useMemoCache;
+}
+
+{
+ HooksDispatcher.useHostTransitionStatus = useHostTransitionStatus;
+}
+
+{
+ HooksDispatcher.useOptimistic = useOptimistic;
+ HooksDispatcher.useFormState = useFormState;
+}
+
+let currentResumableState = null;
+function setCurrentResumableState(resumableState) {
+ currentResumableState = resumableState;
+}
+
+function getCacheSignal() {
+ throw new Error('Not implemented.');
+}
+
+function getCacheForType(resourceType) {
+ throw new Error('Not implemented.');
+}
+
+const DefaultCacheDispatcher = {
+ getCacheSignal,
+ getCacheForType
+};
+
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
+const ReactCurrentCache = ReactSharedInternals.ReactCurrentCache;
+// The name might be minified but we assume that it's going to be the same generated name. Typically
+// because it's just the same compiled output in practice.
+// resume with segmentID at the index
+
+const CLIENT_RENDERED = 4; // if it errors or infinitely suspends
+
+const PENDING = 0;
+const COMPLETED = 1;
+const FLUSHED = 2;
+const ABORTED = 3;
+const ERRORED = 4;
+const POSTPONED = 5;
+const OPEN = 0;
+const CLOSING = 1;
+const CLOSED = 2; // This is a default heuristic for how to split up the HTML content into progressive
+// loading. Our goal is to be able to display additional new content about every 500ms.
+// Faster than that is unnecessary and should be throttled on the client. It also
+// adds unnecessary overhead to do more splits. We don't know if it's a higher or lower
+// end device but higher end suffer less from the overhead than lower end does from
+// not getting small enough pieces. We error on the side of low end.
+// We base this on low end 3G speeds which is about 500kbits per second. We assume
+// that there can be a reasonable drop off from max bandwidth which leaves you with
+// as little as 80%. We can receive half of that each 500ms - at best. In practice,
+// a little bandwidth is lost to processing and contention - e.g. CSS and images that
+// are downloaded along with the main content. So we estimate about half of that to be
+// the lower end throughput. In other words, we expect that you can at least show
+// about 12.5kb of content per 500ms. Not counting starting latency for the first
+// paint.
+// 500 * 1024 / 8 * .8 * 0.5 / 2
+
+const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
+
+function defaultErrorHandler(error) {
+ console['error'](error); // Don't transform to our wrapper
+
+ return null;
+}
+
+function noop() {}
+
+function createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, formState) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState,
+ renderState,
+ rootFormatContext,
+ progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: 0,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: formState === undefined ? null : formState
+ }; // This segment represents the root fallback.
+
+ const rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false); // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+let currentRequest = null;
+function resolveRequest() {
+ if (currentRequest) return currentRequest;
+
+ return null;
+}
+
+function pingTask(request, task) {
+ const pingedTasks = request.pingedTasks;
+ pingedTasks.push(task);
+
+ if (request.pingedTasks.length === 1) {
+ request.flushScheduled = request.destination !== null;
+ scheduleWork(() => performWork(request));
+ }
+}
+
+function createSuspenseBoundary(request, fallbackAbortableTasks) {
+ return {
+ status: PENDING,
+ rootSegmentID: -1,
+ parentFlushed: false,
+ pendingTasks: 0,
+ completedSegments: [],
+ byteSize: 0,
+ fallbackAbortableTasks,
+ errorDigest: null,
+ resources: createBoundaryResources(),
+ trackedContentKeyPath: null,
+ trackedFallbackNode: null
+ };
+}
+
+function createRenderTask(request, thenableState, node, childIndex, blockedBoundary, blockedSegment, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ const task = {
+ replay: null,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createReplayTask(request, thenableState, replay, node, childIndex, blockedBoundary, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ replay.pendingTasks++;
+ const task = {
+ replay,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment: null,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createPendingSegment(request, index, boundary, parentFormatContext, lastPushedText, textEmbedded) {
+ return {
+ status: PENDING,
+ id: -1,
+ // lazily assigned later
+ index,
+ parentFlushed: false,
+ chunks: [],
+ children: [],
+ parentFormatContext,
+ boundary,
+ lastPushedText,
+ textEmbedded
+ };
+} // DEV-only global reference to the currently executing task
+
+function popComponentStackInDEV(task) {
+} // stash the component stack of an unwinding error until it is processed
+
+function logPostpone(request, reason) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ request.onPostpone(reason);
+}
+
+function logRecoverableError(request, error) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ const errorDigest = request.onError(error);
+
+ if (errorDigest != null && typeof errorDigest !== 'string') {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead");
+ }
+
+ return errorDigest;
+}
+
+function fatalError(request, error) {
+ // This is called outside error handling code such as if the root errors outside
+ // a suspense boundary or if the root suspense boundary's fallback errors.
+ // It's also called if React itself or its host configs errors.
+ const onShellError = request.onShellError;
+ onShellError(error);
+ const onFatalError = request.onFatalError;
+ onFatalError(error);
+
+ if (request.destination !== null) {
+ request.status = CLOSED;
+ closeWithError(request.destination, error);
+ } else {
+ request.status = CLOSING;
+ request.fatalError = error;
+ }
+}
+
+function renderSuspenseBoundary(request, someTask, keyPath, props) {
+ if (someTask.replay !== null) {
+ // If we're replaying through this pass, it means we're replaying through
+ // an already completed Suspense boundary. It's too late to do anything about it
+ // so we can just render through it.
+ const prevKeyPath = someTask.keyPath;
+ someTask.keyPath = keyPath;
+ const content = props.children;
+
+ try {
+ renderNode(request, someTask, content, -1);
+ } finally {
+ someTask.keyPath = prevKeyPath;
+ }
+
+ return;
+ } // $FlowFixMe: Refined.
+
+
+ const task = someTask;
+ const prevKeyPath = task.keyPath;
+ const parentBoundary = task.blockedBoundary;
+ const parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for
+ // the fallback so that we can later replace that segment with the content.
+ // This also lets us split out the main content even if it doesn't suspend,
+ // in case it ends up generating a large subtree of content.
+
+ const fallback = props.fallback;
+ const content = props.children;
+ const fallbackAbortSet = new Set();
+ const newBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+
+ if (request.trackedPostpones !== null) {
+ newBoundary.trackedContentKeyPath = keyPath;
+ }
+
+ const insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback.
+
+ const boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false);
+ parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent
+
+ parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately.
+
+ const contentRootSegment = createPendingSegment(request, 0, null, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is
+ // no parent segment so there's nothing to wait on.
+
+ contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks.
+ // I suspect that there might be some efficiency benefits from not creating the suspended task
+ // and instead just using the stack if possible.
+ // TODO: Call this directly instead of messing with saving and restoring contexts.
+ // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and which segment
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = newBoundary;
+ task.blockedSegment = contentRootSegment;
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, newBoundary.resources);
+ }
+
+ task.keyPath = keyPath;
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+ pushSegmentFinale(contentRootSegment.chunks, request.renderState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded);
+ contentRootSegment.status = COMPLETED;
+ queueCompletedSegment(newBoundary, contentRootSegment);
+
+ if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
+ newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ contentRootSegment.status = ERRORED;
+ newBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ newBoundary.errorDigest = errorDigest;
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.blockedSegment = parentSegment;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]];
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones !== null) {
+ // We create a detached replay node to track any postpones inside the fallback.
+ const fallbackReplayNode = [fallbackKeyPath[1], fallbackKeyPath[2], [], null];
+ trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
+
+ if (newBoundary.status === POSTPONED) {
+ // This must exist now.
+ const boundaryReplayNode = trackedPostpones.workingMap.get(keyPath);
+ boundaryReplayNode[4] = fallbackReplayNode;
+ } else {
+ // We might not inject it into the postponed tree, unless the content actually
+ // postpones too. We need to keep track of it until that happpens.
+ newBoundary.trackedFallbackNode = fallbackReplayNode;
+ }
+ } // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+
+ const suspendedFallbackTask = createRenderTask(request, null, fallback, -1, parentBoundary, boundarySegment, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function replaySuspenseBoundary(request, task, keyPath, props, id, childNodes, childSlots, fallbackNodes, fallbackSlots) {
+ const prevKeyPath = task.keyPath;
+ const previousReplaySet = task.replay;
+ const parentBoundary = task.blockedBoundary;
+ const content = props.children;
+ const fallback = props.fallback;
+ const fallbackAbortSet = new Set();
+ const resumedBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = id; // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and replay node
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = resumedBoundary;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, resumedBoundary.resources);
+ }
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+
+ if (resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING) {
+ resumedBoundary.status = COMPLETED;
+ request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ resumedBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ resumedBoundary.errorDigest = errorDigest;
+
+ task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted.
+
+ request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task.
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.replay = previousReplaySet;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+ const fallbackReplay = {
+ nodes: fallbackNodes,
+ slots: fallbackSlots,
+ pendingTasks: 0
+ };
+ const suspendedFallbackTask = createReplayTask(request, null, fallbackReplay, fallback, -1, parentBoundary, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function renderHostElement(request, task, keyPath, type, props) {
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ const children = props.children; // TODO: Make this a Config for replaying.
+
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ } else {
+ // Render
+ const children = pushStartInstance(segment.chunks, type, props, request.resumableState, request.renderState, task.formatContext, segment.lastPushedText);
+ segment.lastPushedText = false;
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ pushEndInstance(segment.chunks, type, props, request.resumableState, prevContext);
+ segment.lastPushedText = false;
+ }
+}
+
+function shouldConstruct(Component) {
+ return Component.prototype && Component.prototype.isReactComponent;
+}
+
+function renderWithHooks(request, task, keyPath, prevThenableState, Component, props, secondArg) {
+ const componentIdentity = {};
+ prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState);
+ const result = Component(props, secondArg);
+ return finishHooks(Component, props, result, secondArg);
+}
+
+function finishClassComponent(request, task, keyPath, instance, Component, props) {
+ const nextChildren = instance.render();
+
+ {
+ const childContextTypes = Component.childContextTypes;
+
+ if (childContextTypes !== null && childContextTypes !== undefined) {
+ const previousContext = task.legacyContext;
+ const mergedContext = processChildContext(instance, Component, previousContext, childContextTypes);
+ task.legacyContext = mergedContext;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.legacyContext = previousContext;
+ return;
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderClassComponent(request, task, keyPath, Component, props) {
+ const maskedContext = getMaskedContext(Component, task.legacyContext) ;
+ const instance = constructClassInstance(Component, props, maskedContext);
+ mountClassInstance(instance, Component, props, maskedContext);
+ finishClassComponent(request, task, keyPath, instance, Component);
+}
+// components for some reason.
+
+function renderIndeterminateComponent(request, task, keyPath, prevThenableState, Component, props) {
+ let legacyContext;
+
+ {
+ legacyContext = getMaskedContext(Component, task.legacyContext);
+ }
+
+ const value = renderWithHooks(request, task, keyPath, prevThenableState, Component, props, legacyContext);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+
+ if ( // Run these checks in production only if the flag is off.
+ // Eventually we'll delete this branch altogether.
+ typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
+
+ mountClassInstance(value, Component, props, legacyContext);
+ finishClassComponent(request, task, keyPath, value, Component);
+ } else {
+
+ finishFunctionComponent(request, task, keyPath, value, hasId, formStateCount, formStateMatchingIndex);
+ }
+}
+
+function finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex) {
+ let didEmitFormStateMarkers = false;
+
+ if (formStateCount !== 0 && request.formState !== null) {
+ // For each useFormState hook, emit a marker that indicates whether we
+ // rendered using the form state passed at the root. We only emit these
+ // markers if form state is passed at the root.
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ didEmitFormStateMarkers = true;
+ const target = segment.chunks;
+
+ for (let i = 0; i < formStateCount; i++) {
+ if (i === formStateMatchingIndex) {
+ pushFormStateMarkerIsMatching(target);
+ } else {
+ pushFormStateMarkerIsNotMatching(target);
+ }
+ }
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+
+ if (hasId) {
+ // This component materialized an id. We treat this as its own level, with
+ // a single "child" slot.
+ const prevTreeContext = task.treeContext;
+ const totalChildren = 1;
+ const index = 0; // Modify the id context. Because we'll need to reset this if something
+ // suspends or errors, we'll use the non-destructive render path.
+
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
+ renderNode(request, task, children, -1); // Like the other contexts, this does not need to be in a finally block
+ // because renderNode takes care of unwinding the stack.
+
+ task.treeContext = prevTreeContext;
+ } else if (didEmitFormStateMarkers) {
+ // If there were formState hooks, we must use the non-destructive path
+ // because this component is not a pure indirection; we emitted markers
+ // to the stream.
+ renderNode(request, task, children, -1);
+ } else {
+ // We're now successfully past this task, and we haven't modified the
+ // context stack. We don't have to pop back to the previous task every
+ // again, so we can use the destructive recursive form.
+ renderNodeDestructive(request, task, null, children, -1);
+ }
+
+ task.keyPath = prevKeyPath;
+}
+
+function resolveDefaultProps(Component, baseProps) {
+ if (Component && Component.defaultProps) {
+ // Resolve default props. Taken from ReactElement
+ const props = assign({}, baseProps);
+ const defaultProps = Component.defaultProps;
+
+ for (const propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+
+ return props;
+ }
+
+ return baseProps;
+}
+
+function renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref) {
+ const children = renderWithHooks(request, task, keyPath, prevThenableState, type.render, props, ref);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+ finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex);
+}
+
+function renderMemo(request, task, keyPath, prevThenableState, type, props, ref) {
+ const innerType = type.type;
+ const resolvedProps = resolveDefaultProps(innerType, props);
+ renderElement(request, task, keyPath, prevThenableState, innerType, resolvedProps, ref);
+}
+
+function renderContextConsumer(request, task, keyPath, context, props) {
+
+ const render = props.children;
+
+ const newValue = readContext$1(context);
+ const newChildren = render(newValue);
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, newChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderContextProvider(request, task, keyPath, type, props) {
+ const context = type._context;
+ const value = props.value;
+ const children = props.children;
+
+ const prevKeyPath = task.keyPath;
+ task.context = pushProvider(context, value);
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, children, -1);
+ task.context = popProvider();
+ task.keyPath = prevKeyPath;
+}
+
+function renderLazyComponent(request, task, keyPath, prevThenableState, lazyComponent, props, ref) {
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+ const Component = init(payload);
+ const resolvedProps = resolveDefaultProps(Component, props);
+ renderElement(request, task, keyPath, prevThenableState, Component, resolvedProps, ref);
+}
+
+function renderOffscreen(request, task, keyPath, props) {
+ const mode = props.mode;
+
+ if (mode === 'hidden') ; else {
+ // A visible Offscreen boundary is treated exactly like a fragment: a
+ // pure indirection.
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ }
+}
+
+function renderElement(request, task, keyPath, prevThenableState, type, props, ref) {
+ if (typeof type === 'function') {
+ if (shouldConstruct(type)) {
+ renderClassComponent(request, task, keyPath, type, props);
+ return;
+ } else {
+ renderIndeterminateComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+
+ if (typeof type === 'string') {
+ renderHostElement(request, task, keyPath, type, props);
+ return;
+ }
+
+ switch (type) {
+ // LegacyHidden acts the same as a fragment. This only works because we
+ // currently assume that every instance of LegacyHidden is accompanied by a
+ // host component wrapper. In the hidden mode, the host component is given a
+ // `hidden` attribute, which ensures that the initial HTML is not visible.
+ // To support the use of LegacyHidden as a true fragment, without an extra
+ // DOM node, we would have to hide the initial HTML in some other way.
+ // TODO: Delete in LegacyHidden. It's an unstable API only used in the
+ // www build. As a migration step, we could add a special prop to Offscreen
+ // that simulates the old behavior (no hiding, no change to effects).
+ case REACT_LEGACY_HIDDEN_TYPE:
+ case REACT_DEBUG_TRACING_MODE_TYPE:
+ case REACT_STRICT_MODE_TYPE:
+ case REACT_PROFILER_TYPE:
+ case REACT_FRAGMENT_TYPE:
+ {
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_OFFSCREEN_TYPE:
+ {
+ renderOffscreen(request, task, keyPath, props);
+ return;
+ }
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ {
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_SCOPE_TYPE:
+ {
+
+ throw new Error('ReactDOMServer does not yet support scope components.');
+ }
+
+ case REACT_SUSPENSE_TYPE:
+ {
+ {
+ renderSuspenseBoundary(request, task, keyPath, props);
+ }
+
+ return;
+ }
+ }
+
+ if (typeof type === 'object' && type !== null) {
+ switch (type.$$typeof) {
+ case REACT_FORWARD_REF_TYPE:
+ {
+ renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_MEMO_TYPE:
+ {
+ renderMemo(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_PROVIDER_TYPE:
+ {
+ renderContextProvider(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_CONTEXT_TYPE:
+ {
+ renderContextConsumer(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_LAZY_TYPE:
+ {
+ renderLazyComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+ }
+
+ let info = '';
+
+ throw new Error('Element type is invalid: expected a string (for built-in ' + 'components) or a class/function (for composite components) ' + ("but got: " + (type == null ? type : typeof type) + "." + info));
+}
+
+function resumeNode(request, task, segmentId, node, childIndex) {
+ const prevReplay = task.replay;
+ const blockedBoundary = task.blockedBoundary;
+ const resumedSegment = createPendingSegment(request, 0, null, task.formatContext, false, false);
+ resumedSegment.id = segmentId;
+ resumedSegment.parentFlushed = true;
+
+ try {
+ // Convert the current ReplayTask to a RenderTask.
+ const renderTask = task;
+ renderTask.replay = null;
+ renderTask.blockedSegment = resumedSegment;
+ renderNode(request, task, node, childIndex);
+ resumedSegment.status = COMPLETED;
+
+ if (blockedBoundary === null) {
+ request.completedRootSegment = resumedSegment;
+ } else {
+ queueCompletedSegment(blockedBoundary, resumedSegment);
+
+ if (blockedBoundary.parentFlushed) {
+ request.partialBoundaries.push(blockedBoundary);
+ }
+ }
+ } finally {
+ // Restore to a ReplayTask.
+ task.replay = prevReplay;
+ task.blockedSegment = null;
+ }
+}
+
+function replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, replay) {
+ // We're replaying. Find the path to follow.
+ const replayNodes = replay.nodes;
+
+ for (let i = 0; i < replayNodes.length; i++) {
+ // Flow doesn't support refinement on tuples so we do it manually here.
+ const node = replayNodes[i];
+
+ if (keyOrIndex !== node[1]) {
+ continue;
+ }
+
+ if (node.length === 4) {
+ // Matched a replayable path.
+ // Let's double check that the component name matches as a precaution.
+ if (name !== null && name !== node[0]) {
+ throw new Error('Expected the resume to render <' + node[0] + '> in this slot but instead it rendered <' + name + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ const currentNode = task.node;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0 // TODO check remaining slots
+ ) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ if (task.node === currentNode) {
+ // This same element suspended so we need to pop the replay we just added.
+ task.replay = replay;
+ }
+
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay;
+ } else {
+ // Let's double check that the component type matches.
+ if (type !== REACT_SUSPENSE_TYPE) {
+ const expectedType = 'Suspense';
+ throw new Error('Expected the resume to render <' + expectedType + '> in this slot but instead it rendered <' + (getComponentNameFromType(type) || 'Unknown') + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ } // Matched a replayable path.
+
+
+ replaySuspenseBoundary(request, task, keyPath, props, node[5], node[2], node[3], node[4] === null ? [] : node[4][2], node[4] === null ? null : node[4][3]);
+ } // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+
+ replayNodes.splice(i, 1);
+ return;
+ } // We didn't find any matching nodes. We assume that this element was already
+ // rendered in the prelude and skip it.
+
+} // $FlowFixMe[missing-local-annot]
+
+function renderNodeDestructive(request, task, // The thenable state reused from the previous attempt, if any. This is almost
+// always null, except when called by retryTask.
+prevThenableState, node, childIndex) {
+ {
+ return renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex);
+ }
+} // This function by it self renders a node and consumes the task by mutating it
+// to update the current execution state.
+
+
+function renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex) {
+ if (task.replay !== null && typeof task.replay.slots === 'number') {
+ // TODO: Figure out a cheaper place than this hot path to do this check.
+ const resumeSegmentID = task.replay.slots;
+ resumeNode(request, task, resumeSegmentID, node, childIndex);
+ return;
+ } // Stash the node we're working on. We'll pick up from this task in case
+ // something suspends.
+
+
+ task.node = node;
+ task.childIndex = childIndex; // Handle object types
+
+ if (typeof node === 'object' && node !== null) {
+ switch (node.$$typeof) {
+ case REACT_ELEMENT_TYPE:
+ {
+ const element = node;
+ const type = element.type;
+ const key = element.key;
+ const props = element.props;
+ const ref = element.ref;
+ const name = getComponentNameFromType(type);
+ const keyOrIndex = key == null ? childIndex === -1 ? 0 : childIndex : key;
+ const keyPath = [task.keyPath, name, keyOrIndex];
+
+ if (task.replay !== null) {
+ replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, task.replay); // No matches found for this node. We assume it's already emitted in the
+ // prelude and skip it during the replay.
+ } else {
+ // We're doing a plain render.
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+ }
+
+ return;
+ }
+
+ case REACT_PORTAL_TYPE:
+ throw new Error('Portals are not currently supported by the server renderer. ' + 'Render them conditionally so that they only appear on the client render.');
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyNode = node;
+ const payload = lazyNode._payload;
+ const init = lazyNode._init;
+ let resolvedNode;
+
+ {
+ resolvedNode = init(payload);
+ }
+
+ renderNodeDestructive(request, task, null, resolvedNode, childIndex);
+ return;
+ }
+ }
+
+ if (isArray(node)) {
+ renderChildrenArray(request, task, node, childIndex);
+ return;
+ }
+
+ const iteratorFn = getIteratorFn(node);
+
+ if (iteratorFn) {
+
+ const iterator = iteratorFn.call(node);
+
+ if (iterator) {
+ // We need to know how many total children are in this set, so that we
+ // can allocate enough id slots to acommodate them. So we must exhaust
+ // the iterator before we start recursively rendering the children.
+ // TODO: This is not great but I think it's inherent to the id
+ // generation algorithm.
+ let step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that.
+
+ if (!step.done) {
+ const children = [];
+
+ do {
+ children.push(step.value);
+ step = iterator.next();
+ } while (!step.done);
+
+ renderChildrenArray(request, task, children, childIndex);
+ return;
+ }
+
+ return;
+ }
+ } // Usables are a valid React node type. When React encounters a Usable in
+ // a child position, it unwraps it using the same algorithm as `use`. For
+ // example, for promises, React will throw an exception to unwind the
+ // stack, then replay the component once the promise resolves.
+ //
+ // A difference from `use` is that React will keep unwrapping the value
+ // until it reaches a non-Usable type.
+ //
+ // e.g. Usable>> should resolve to T
+
+
+ const maybeUsable = node;
+
+ if (typeof maybeUsable.then === 'function') {
+ const thenable = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable), childIndex);
+ }
+
+ if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, readContext$1(context), childIndex);
+ } // $FlowFixMe[method-unbinding]
+
+
+ const childString = Object.prototype.toString.call(node);
+ throw new Error("Objects are not valid as a React child (found: " + (childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString) + "). " + 'If you meant to render a collection of children, use an array ' + 'instead.');
+ }
+
+ if (typeof node === 'string') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+
+ if (typeof node === 'number') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, '' + node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+}
+
+function replayFragment(request, task, children, childIndex) {
+ // If we're supposed follow this array, we'd expect to see a ReplayNode matching
+ // this fragment.
+ const replay = task.replay;
+ const replayNodes = replay.nodes;
+
+ for (let j = 0; j < replayNodes.length; j++) {
+ const node = replayNodes[j];
+
+ if (node[1] !== childIndex) {
+ continue;
+ } // Matched a replayable path.
+
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderChildrenArray(request, task, children, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+ // This is an error, stash the component stack if it is null.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay; // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ replayNodes.splice(j, 1);
+ break;
+ }
+}
+
+function renderChildrenArray(request, task, children, childIndex) {
+ const prevKeyPath = task.keyPath;
+
+ if (childIndex !== -1) {
+ task.keyPath = [task.keyPath, 'Fragment', childIndex];
+
+ if (task.replay !== null) {
+ replayFragment(request, // $FlowFixMe: Refined.
+ task, children, childIndex);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ const prevTreeContext = task.treeContext;
+ const totalChildren = children.length;
+
+ if (task.replay !== null) {
+ // Replay
+ // First we need to check if we have any resume slots at this level.
+ const resumeSlots = task.replay.slots;
+
+ if (resumeSlots !== null && typeof resumeSlots === 'object') {
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ const resumeSegmentID = resumeSlots[i]; // TODO: If this errors we should still continue with the next sibling.
+
+ if (typeof resumeSegmentID === 'number') {
+ resumeNode(request, task, resumeSegmentID, node, i); // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ delete resumeSlots[i];
+ } else {
+ renderNode(request, task, node, i);
+ }
+ }
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ renderNode(request, task, node, i);
+ } // Because this context is always set right before rendering every child, we
+ // only need to reset it to the previous value at the very end.
+
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+}
+
+function trackPostpone(request, trackedPostpones, task, segment) {
+ segment.status = POSTPONED;
+ const keyPath = task.keyPath;
+ const boundary = task.blockedBoundary;
+
+ if (boundary === null) {
+ segment.id = request.nextSegmentId++;
+ trackedPostpones.rootSlots = segment.id;
+
+ if (request.completedRootSegment !== null) {
+ // Postpone the root if this was a deeper segment.
+ request.completedRootSegment.status = POSTPONED;
+ }
+
+ return;
+ }
+
+ if (boundary !== null && boundary.status === PENDING) {
+ boundary.status = POSTPONED; // We need to eagerly assign it an ID because we'll need to refer to
+ // it before flushing and we know that we can't inline it.
+
+ boundary.rootSegmentID = request.nextSegmentId++;
+ const boundaryKeyPath = boundary.trackedContentKeyPath;
+
+ if (boundaryKeyPath === null) {
+ throw new Error('It should not be possible to postpone at the root. This is a bug in React.');
+ }
+
+ const fallbackReplayNode = boundary.trackedFallbackNode;
+ const children = [];
+
+ if (boundaryKeyPath === keyPath && task.childIndex === -1) {
+ // Since we postponed directly in the Suspense boundary we can't have written anything
+ // to its segment. Therefore this will end up becoming the root segment.
+ segment.id = boundary.rootSegmentID; // We postponed directly inside the Suspense boundary so we mark this for resuming.
+
+ const boundaryNode = [boundaryKeyPath[1], boundaryKeyPath[2], children, boundary.rootSegmentID, fallbackReplayNode, boundary.rootSegmentID];
+ trackedPostpones.workingMap.set(boundaryKeyPath, boundaryNode);
+ addToReplayParent(boundaryNode, boundaryKeyPath[0], trackedPostpones);
+ return;
+ } else {
+ let boundaryNode = trackedPostpones.workingMap.get(boundaryKeyPath);
+
+ if (boundaryNode === undefined) {
+ boundaryNode = [boundaryKeyPath[1], boundaryKeyPath[2], children, null, fallbackReplayNode, boundary.rootSegmentID];
+ trackedPostpones.workingMap.set(boundaryKeyPath, boundaryNode);
+ addToReplayParent(boundaryNode, boundaryKeyPath[0], trackedPostpones);
+ } else {
+ // Upgrade to ReplaySuspenseBoundary.
+ const suspenseBoundary = boundaryNode;
+ suspenseBoundary[4] = fallbackReplayNode;
+ suspenseBoundary[5] = boundary.rootSegmentID;
+ } // Fall through to add the child node.
+
+ }
+ } // We know that this will leave a hole so we might as well assign an ID now.
+ // We might have one already if we had a parent that gave us its ID.
+
+
+ if (segment.id === -1) {
+ if (segment.parentFlushed && boundary !== null) {
+ // If this segment's parent was already flushed, it means we really just
+ // skipped the parent and this segment is now the root.
+ segment.id = boundary.rootSegmentID;
+ } else {
+ segment.id = request.nextSegmentId++;
+ }
+ }
+
+ if (task.childIndex === -1) {
+ // Resume starting from directly inside the previous parent element.
+ if (keyPath === null) {
+ trackedPostpones.rootSlots = segment.id;
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let resumableNode = workingMap.get(keyPath);
+
+ if (resumableNode === undefined) {
+ resumableNode = [keyPath[1], keyPath[2], [], segment.id];
+ addToReplayParent(resumableNode, keyPath[0], trackedPostpones);
+ } else {
+ resumableNode[3] = segment.id;
+ }
+ }
+ } else {
+ let slots;
+
+ if (keyPath === null) {
+ slots = trackedPostpones.rootSlots;
+
+ if (slots === null) {
+ slots = trackedPostpones.rootSlots = {};
+ } else if (typeof slots === 'number') {
+ throw new Error('It should not be possible to postpone both at the root of an element ' + 'as well as a slot below. This is a bug in React.');
+ }
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let resumableNode = workingMap.get(keyPath);
+
+ if (resumableNode === undefined) {
+ slots = {};
+ resumableNode = [keyPath[1], keyPath[2], [], slots];
+ workingMap.set(keyPath, resumableNode);
+ addToReplayParent(resumableNode, keyPath[0], trackedPostpones);
+ } else {
+ slots = resumableNode[3];
+
+ if (slots === null) {
+ slots = resumableNode[3] = {};
+ } else if (typeof slots === 'number') {
+ throw new Error('It should not be possible to postpone both at the root of an element ' + 'as well as a slot below. This is a bug in React.');
+ }
+ }
+ }
+
+ slots[task.childIndex] = segment.id;
+ }
+}
+
+function injectPostponedHole(request, task, reason) {
+ logPostpone(request, reason); // Something suspended, we'll need to create a new segment and resolve it later.
+
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ return newSegment;
+}
+
+function spawnNewSuspendedReplayTask(request, task, thenableState, x) {
+ const newTask = createReplayTask(request, thenableState, task.replay, task.node, task.childIndex, task.blockedBoundary, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+}
+
+function spawnNewSuspendedRenderTask(request, task, thenableState, x) {
+ // Something suspended, we'll need to create a new segment and resolve it later.
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ const newTask = createRenderTask(request, thenableState, task.node, task.childIndex, task.blockedBoundary, newSegment, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+} // This is a non-destructive form of rendering a node. If it suspends it spawns
+// a new task and restores the context of this task to what it was before.
+
+
+function renderNode(request, task, node, childIndex) {
+ // Snapshot the current context in case something throws to interrupt the
+ // process.
+ const previousFormatContext = task.formatContext;
+ const previousLegacyContext = task.legacyContext;
+ const previousContext = task.context;
+ const previousKeyPath = task.keyPath;
+ const previousTreeContext = task.treeContext;
+
+ let x; // Store how much we've pushed at this point so we can reset it in case something
+ // suspended partially through writing something.
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState();
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedReplayTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode.
+
+ }
+ } else {
+ // Render
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedRenderTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+
+ if (request.trackedPostpones !== null && x.$$typeof === REACT_POSTPONE_TYPE && task.blockedBoundary !== null // bubble if we're postponing in the shell
+ ) {
+ // If we're tracking postpones, we inject a hole here and continue rendering
+ // sibling. Similar to suspending. If we're not tracking, we treat it more like
+ // an error. Notably this doesn't spawn a new task since nothing will fill it
+ // in during this prerender.
+ const postponeInstance = x;
+ const trackedPostpones = request.trackedPostpones;
+ const postponedSegment = injectPostponedHole(request, task, // We don't use ReplayTasks in prerenders.
+ postponeInstance.message);
+ trackPostpone(request, trackedPostpones, task, postponedSegment); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ return;
+ }
+ }
+ }
+ } // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ // Let's terminate the rest of the tree and don't render any siblings.
+
+
+ throw x;
+}
+
+function erroredReplay(request, boundary, error, replayNodes, resumeSlots) {
+ // Erroring during a replay doesn't actually cause an error by itself because
+ // that component has already rendered. What causes the error is the resumable
+ // points that we did not yet finish which will be below the point of the reset.
+ // For example, if we're replaying a path to a Suspense boundary that is not done
+ // that doesn't error the parent Suspense boundary.
+ // This might be a bit strange that the error in a parent gets thrown at a child.
+ // We log it only once and reuse the digest.
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ abortRemainingReplayNodes(request, boundary, replayNodes, resumeSlots, error, errorDigest);
+}
+
+function erroredTask(request, boundary, error) {
+ // Report the error to a global handler.
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ if (boundary === null) {
+ fatalError(request, error);
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+ // so we can flush it, if the parent already flushed.
+
+
+ if (boundary.parentFlushed) {
+ // We don't have a preference where in the queue this goes since it's likely
+ // to error on the client anyway. However, intentionally client-rendered
+ // boundaries should be flushed earlier so that they can start on the client.
+ // We reuse the same queue for errors.
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function abortTaskSoft(task) {
+ // This aborts task without aborting the parent boundary that it blocks.
+ // It's used for when we didn't need this task to complete the tree.
+ // If task was needed, then it should use abortTask instead.
+ const request = this;
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ finishedTask(request, boundary, segment);
+ }
+}
+
+function abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest) {
+ const resumedBoundary = createSuspenseBoundary(request, new Set());
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = rootSegmentID;
+ resumedBoundary.status = CLIENT_RENDERED;
+ resumedBoundary.errorDigest = errorDigest;
+
+ if (resumedBoundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(resumedBoundary);
+ }
+}
+
+function abortRemainingReplayNodes(request, boundary, nodes, slots, error, errorDigest) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+
+ if (node.length === 4) {
+ abortRemainingReplayNodes(request, boundary, node[2], node[3], error, errorDigest);
+ } else {
+ const boundaryNode = node;
+ const rootSegmentID = boundaryNode[5];
+ abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest);
+ }
+ } // Empty the set, since we've cleared it now.
+
+
+ nodes.length = 0;
+
+ if (slots !== null) {
+ // We had something still to resume in the parent boundary. We must trigger
+ // the error on the parent boundary since it's not able to complete.
+ if (boundary === null) {
+ throw new Error('We should not have any resumable nodes in the shell. ' + 'This is a bug in React.');
+ } else if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // Empty the set
+
+
+ if (typeof slots === 'object') {
+ for (const index in slots) {
+ delete slots[index];
+ }
+ }
+ }
+}
+
+function abortTask(task, request, error) {
+ // This aborts the task and aborts the parent that it blocks, putting it into
+ // client rendered mode.
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ }
+
+ if (boundary === null) {
+ if (request.status !== CLOSING && request.status !== CLOSED) {
+ const replay = task.replay;
+
+ if (replay === null) {
+ // We didn't complete the root so we have nothing to show. We can close
+ // the request;
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ return;
+ } else {
+ // If the shell aborts during a replay, that's not a fatal error. Instead
+ // we should be able to recover by client rendering all the root boundaries in
+ // the ReplaySet.
+ replay.pendingTasks--;
+
+ if (replay.pendingTasks === 0 && replay.nodes.length > 0) {
+ const errorDigest = logRecoverableError(request, error);
+ abortRemainingReplayNodes(request, null, replay.nodes, replay.slots, error, errorDigest);
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ }
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = logRecoverableError(request, error);
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // If this boundary was still pending then we haven't already cancelled its fallbacks.
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
+
+
+ boundary.fallbackAbortableTasks.forEach(fallbackTask => abortTask(fallbackTask, request, error));
+ boundary.fallbackAbortableTasks.clear();
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeShell(request) {
+ if (request.trackedPostpones === null) {
+ // We only emit early preloads on shell completion for renders. For prerenders
+ // we wait for the entire Request to finish because we are not responding to a
+ // live request and can wait for as much data as possible.
+ // we should only be calling completeShell when the shell is complete so we
+ // just use a literal here
+ const shellComplete = true;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ } // We have completed the shell so the shell can't error anymore.
+
+
+ request.onShellError = noop;
+ const onShellReady = request.onShellReady;
+ onShellReady();
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeAll(request) {
+ // During a render the shell must be complete if the entire request is finished
+ // however during a Prerender it is possible that the shell is incomplete because
+ // it postponed. We cannot use rootPendingTasks in the prerender case because
+ // those hit zero even when the shell postpones. Instead we look at the completedRootSegment
+ const shellComplete = request.trackedPostpones === null ? // Render, we assume it is completed
+ true : // Prerender Request, we use the state of the root segment
+ request.completedRootSegment === null || request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ const onAllReady = request.onAllReady;
+ onAllReady();
+}
+
+function queueCompletedSegment(boundary, segment) {
+ if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) {
+ // This is an empty segment. There's nothing to write, so we can instead transfer the ID
+ // to the child. That way any existing references point to the child.
+ const childSegment = segment.children[0];
+ childSegment.id = segment.id;
+ childSegment.parentFlushed = true;
+
+ if (childSegment.status === COMPLETED) {
+ queueCompletedSegment(boundary, childSegment);
+ }
+ } else {
+ const completedSegments = boundary.completedSegments;
+ completedSegments.push(segment);
+ }
+}
+
+function finishedTask(request, boundary, segment) {
+ if (boundary === null) {
+ if (segment !== null && segment.parentFlushed) {
+ if (request.completedRootSegment !== null) {
+ throw new Error('There can only be one root segment. This is a bug in React.');
+ }
+
+ request.completedRootSegment = segment;
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status === CLIENT_RENDERED) ; else if (boundary.pendingTasks === 0) {
+ if (boundary.status === PENDING) {
+ boundary.status = COMPLETED;
+ } // This must have been the last segment we were waiting on. This boundary is now complete.
+
+
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent segment already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ }
+ }
+
+ if (boundary.parentFlushed) {
+ // The segment might be part of a segment that didn't flush yet, but if the boundary's
+ // parent flushed, we need to schedule the boundary to be emitted.
+ request.completedBoundaries.push(boundary);
+ } // We can now cancel any pending task on the fallback since we won't need to show it anymore.
+ // This needs to happen after we read the parentFlushed flags because aborting can finish
+ // work which can trigger user code, which can start flushing, which can change those flags.
+ // If the boundary was POSTPONED, we still need to finish the fallback first.
+
+
+ if (boundary.status === COMPLETED) {
+ boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
+ boundary.fallbackAbortableTasks.clear();
+ }
+ } else {
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length === 1) {
+ // This is the first time since we last flushed that we completed anything.
+ // We can schedule this boundary to emit its partially completed segments early
+ // in case the parent has already been flushed.
+ if (boundary.parentFlushed) {
+ request.partialBoundaries.push(boundary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function retryTask(request, task) {
+ {
+ const blockedBoundary = task.blockedBoundary;
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, blockedBoundary ? blockedBoundary.resources : null);
+ }
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ retryReplayTask(request, // $FlowFixMe: Refined.
+ task);
+ } else {
+ retryRenderTask(request, // $FlowFixMe: Refined.
+ task, segment);
+ }
+}
+
+function retryRenderTask(request, task, segment) {
+ if (segment.status !== PENDING) {
+ // We completed this by other means before we had a chance to retry it.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+ pushSegmentFinale(segment.chunks, request.renderState, segment.lastPushedText, segment.textEmbedded);
+ task.abortSet.delete(task);
+ segment.status = COMPLETED;
+ finishedTask(request, task.blockedBoundary, segment);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ } else if (request.trackedPostpones !== null && x.$$typeof === REACT_POSTPONE_TYPE) {
+ // If we're tracking postpones, we mark this segment as postponed and finish
+ // the task without filling it in. If we're not tracking, we treat it more like
+ // an error.
+ const trackedPostpones = request.trackedPostpones;
+ task.abortSet.delete(task);
+ const postponeInstance = x;
+ logPostpone(request, postponeInstance.message);
+ trackPostpone(request, trackedPostpones, task, segment);
+ finishedTask(request, task.blockedBoundary, segment);
+ return;
+ }
+ }
+
+ task.abortSet.delete(task);
+ segment.status = ERRORED;
+ erroredTask(request, task.blockedBoundary, x);
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function retryReplayTask(request, task) {
+ if (task.replay.pendingTasks === 0) {
+ // There are no pending tasks working on this set, so we must have aborted.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ finishedTask(request, task.blockedBoundary, null);
+ } catch (thrownValue) {
+ resetHooksState();
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ erroredReplay(request, task.blockedBoundary, x, task.replay.nodes, task.replay.slots);
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function performWork(request) {
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ const prevContext = getActiveContext();
+ const prevDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = HooksDispatcher;
+ let prevCacheDispatcher;
+
+ {
+ prevCacheDispatcher = ReactCurrentCache.current;
+ ReactCurrentCache.current = DefaultCacheDispatcher;
+ }
+
+ const prevRequest = currentRequest;
+ currentRequest = request;
+
+ const prevResumableState = currentResumableState;
+ setCurrentResumableState(request.resumableState);
+
+ try {
+ const pingedTasks = request.pingedTasks;
+ let i;
+
+ for (i = 0; i < pingedTasks.length; i++) {
+ const task = pingedTasks[i];
+ retryTask(request, task);
+ }
+
+ pingedTasks.splice(0, i);
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ } finally {
+ setCurrentResumableState(prevResumableState);
+ ReactCurrentDispatcher.current = prevDispatcher;
+
+ {
+ ReactCurrentCache.current = prevCacheDispatcher;
+ }
+
+ if (prevDispatcher === HooksDispatcher) {
+ // This means that we were in a reentrant work loop. This could happen
+ // in a renderer that supports synchronous work like renderToString,
+ // when it's called from within another renderer.
+ // Normally we don't bother switching the contexts to their root/default
+ // values when leaving because we'll likely need the same or similar
+ // context again. However, when we're inside a synchronous loop like this
+ // we'll to restore the context to what it was before returning.
+ switchContext(prevContext);
+ }
+
+ currentRequest = prevRequest;
+ }
+}
+
+function flushSubtree(request, destination, segment) {
+ segment.parentFlushed = true;
+
+ switch (segment.status) {
+ case PENDING:
+ {
+ // We're emitting a placeholder for this segment to be filled in later.
+ // Therefore we'll need to assign it an ID - to refer to it by.
+ segment.id = request.nextSegmentId++; // Fallthrough
+ }
+
+ case POSTPONED:
+ {
+ const segmentID = segment.id; // When this segment finally completes it won't be embedded in text since it will flush separately
+
+ segment.lastPushedText = false;
+ segment.textEmbedded = false;
+ return writePlaceholder(destination, request.renderState, segmentID);
+ }
+
+ case COMPLETED:
+ {
+ segment.status = FLUSHED;
+ let r = true;
+ const chunks = segment.chunks;
+ let chunkIdx = 0;
+ const children = segment.children;
+
+ for (let childIdx = 0; childIdx < children.length; childIdx++) {
+ const nextChild = children[childIdx]; // Write all the chunks up until the next child.
+
+ for (; chunkIdx < nextChild.index; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ r = flushSegment(request, destination, nextChild);
+ } // Finally just write all the remaining chunks
+
+
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ if (chunkIdx < chunks.length) {
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
+ }
+
+ return r;
+ }
+
+ default:
+ {
+ throw new Error('Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.');
+ }
+ }
+}
+
+function flushSegment(request, destination, segment) {
+ const boundary = segment.boundary;
+
+ if (boundary === null) {
+ // Not a suspense boundary.
+ return flushSubtree(request, destination, segment);
+ }
+
+ boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to
+ // emit the content or the fallback now.
+
+ if (boundary.status === CLIENT_RENDERED) {
+ // Emit a client rendered suspense boundary wrapper.
+ // We never queue the inner boundary so we'll never emit its content or partial segments.
+ writeStartClientRenderedSuspenseBoundary(destination, request.renderState, boundary.errorDigest); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndClientRenderedSuspenseBoundary(destination);
+ } else if (boundary.status !== COMPLETED) {
+ if (boundary.status === PENDING) {
+ // For pending boundaries we lazily assign an ID to the boundary
+ // and root segment.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ }
+
+ if (boundary.completedSegments.length > 0) {
+ // If this is at least partially complete, we can queue it to be partially emitted early.
+ request.partialBoundaries.push(boundary);
+ } // This boundary is still loading. Emit a pending suspense boundary wrapper.
+
+
+ const id = boundary.rootSegmentID;
+ writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else if (boundary.byteSize > request.progressiveChunkSize) {
+ // This boundary is large and will be emitted separately so that we can progressively show
+ // other content. We add it to the queue during the flush because we have to ensure that
+ // the parent flushes first so that there's something to inject it into.
+ // We also have to make sure that it's emitted into the queue in a deterministic slot.
+ // I.e. we can't insert it here when it completes.
+ // Assign an ID to refer to the future content by.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper.
+
+ writeStartPendingSuspenseBoundary(destination, request.renderState, boundary.rootSegmentID); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else {
+ {
+ hoistResources(request.renderState, boundary.resources);
+ } // We can inline this boundary's content as a complete boundary.
+
+
+ writeStartCompletedSuspenseBoundary(destination);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length !== 1) {
+ throw new Error('A previously unvisited boundary must have exactly one root segment. This is a bug in React.');
+ }
+
+ const contentSegment = completedSegments[0];
+ flushSegment(request, destination, contentSegment);
+ return writeEndCompletedSuspenseBoundary(destination);
+ }
+}
+
+function flushClientRenderedBoundary(request, destination, boundary) {
+ return writeClientRenderBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack);
+}
+
+function flushSegmentContainer(request, destination, segment) {
+ writeStartSegment(destination, request.renderState, segment.parentFormatContext, segment.id);
+ flushSegment(request, destination, segment);
+ return writeEndSegment(destination, segment.parentFormatContext);
+}
+
+function flushCompletedBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+ flushPartiallyCompletedSegment(request, destination, boundary, segment);
+ }
+
+ completedSegments.length = 0;
+
+ {
+ writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+
+ return writeCompletedBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.resources);
+}
+
+function flushPartialBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+
+ if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) {
+ i++;
+ completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority
+ // might want to write later.
+
+ return false;
+ }
+ }
+
+ completedSegments.splice(0, i);
+
+ {
+ // The way this is structured we only write resources for partial boundaries
+ // if there is no backpressure. Later before we complete the boundary we
+ // will write resources regardless of backpressure before we emit the
+ // completion instruction
+ return writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+}
+
+function flushPartiallyCompletedSegment(request, destination, boundary, segment) {
+ if (segment.status === FLUSHED) {
+ // We've already flushed this inline.
+ return true;
+ }
+
+ const segmentID = segment.id;
+
+ if (segmentID === -1) {
+ // This segment wasn't previously referred to. This happens at the root of
+ // a boundary. We make kind of a leap here and assume this is the root.
+ const rootSegmentID = segment.id = boundary.rootSegmentID;
+
+ if (rootSegmentID === -1) {
+ throw new Error('A root segment ID must have been assigned by now. This is a bug in React.');
+ }
+
+ return flushSegmentContainer(request, destination, segment);
+ } else if (segmentID === boundary.rootSegmentID) {
+ // When we emit postponed boundaries, we might have assigned the ID already
+ // but it's still the root segment so we can't inject it into the parent yet.
+ return flushSegmentContainer(request, destination, segment);
+ } else {
+ flushSegmentContainer(request, destination, segment);
+ return writeCompletedSegmentInstruction(destination, request.resumableState, request.renderState, segmentID);
+ }
+}
+
+function flushCompletedQueues(request, destination) {
+
+ try {
+ // The structure of this is to go through each queue one by one and write
+ // until the sink tells us to stop. When we should stop, we still finish writing
+ // that item fully and then yield. At that point we remove the already completed
+ // items up until the point we completed them.
+ let i;
+ const completedRootSegment = request.completedRootSegment;
+
+ if (completedRootSegment !== null) {
+ if (completedRootSegment.status === POSTPONED) {
+ // We postponed the root, so we write nothing.
+ return;
+ } else if (request.pendingRootTasks === 0) {
+ if (enableFloat) {
+ writePreamble(destination, request.resumableState, request.renderState, request.allPendingTasks === 0 && request.trackedPostpones === null);
+ }
+
+ flushSegment(request, destination, completedRootSegment);
+ request.completedRootSegment = null;
+ writeCompletedRoot(destination, request.renderState, request.resumableState);
+ } else {
+ // We haven't flushed the root yet so we don't need to check any other branches further down
+ return;
+ }
+ }
+
+ if (enableFloat) {
+ writeHoistables(destination, request.resumableState, request.renderState);
+ } // We emit client rendering instructions for already emitted boundaries first.
+ // This is so that we can signal to the client to start client rendering them as
+ // soon as possible.
+
+
+ const clientRenderedBoundaries = request.clientRenderedBoundaries;
+
+ for (i = 0; i < clientRenderedBoundaries.length; i++) {
+ const boundary = clientRenderedBoundaries[i];
+
+ if (!flushClientRenderedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ clientRenderedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries
+ // that are completely done since we can actually show them, than it is to emit
+ // any individual segments from a partially complete boundary.
+
+ const completedBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < completedBoundaries.length; i++) {
+ const boundary = completedBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ completedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before
+ // we continue with lower priorities.
+
+ completeWriting(destination);
+ beginWriting(destination); // TODO: Here we'll emit data used by hydration.
+ // Next we emit any segments of any boundaries that are partially complete
+ // but not deeply complete.
+
+ const partialBoundaries = request.partialBoundaries;
+
+ for (i = 0; i < partialBoundaries.length; i++) {
+ const boundary = partialBoundaries[i];
+
+ if (!flushPartialBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ partialBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had
+ // boundaries added to it in case they were too larged to be inlined.
+ // New ones might be added in this loop.
+
+ const largeBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < largeBoundaries.length; i++) {
+ const boundary = largeBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ largeBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ largeBoundaries.splice(0, i);
+ } finally {
+ if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because
+ // either they have pending task or they're complete.
+ ) {
+ request.flushScheduled = false;
+
+ {
+ // We write the trailing tags but only if don't have any data to resume.
+ // If we need to resume we'll write the postamble in the resume instead.
+ if (request.trackedPostpones === null) {
+ writePostamble(destination, request.resumableState);
+ }
+ }
+
+
+ close(destination); // We need to stop flowing now because we do not want any async contexts which might call
+ // float methods to initiate any flushes after this point
+
+ stopFlowing(request);
+ }
+ }
+}
+
+function startWork(request) {
+ request.flushScheduled = request.destination !== null;
+
+ {
+ scheduleWork(() => performWork(request));
+ }
+
+ if (request.trackedPostpones === null) {
+ // this is either a regular render or a resume. For regular render we want
+ // to call emitEarlyPreloads after the first performWork because we want
+ // are responding to a live request and need to balance sending something early
+ // (i.e. don't want for the shell to finish) but we need something to send.
+ // The only implementation of this is for DOM at the moment and during resumes nothing
+ // actually emits but the code paths here are the same.
+ // During a prerender we don't want to be too aggressive in emitting early preloads
+ // because we aren't responding to a live request and we can wait for the prerender to
+ // postpone before we emit anything.
+ {
+ scheduleWork(() => enqueueEarlyPreloadsAfterInitialWork(request));
+ }
+ }
+}
+
+function enqueueEarlyPreloadsAfterInitialWork(request) {
+ const shellComplete = request.pendingRootTasks === 0;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+
+function enqueueFlush(request) {
+ if (request.flushScheduled === false && // If there are pinged tasks we are going to flush anyway after work completes
+ request.pingedTasks.length === 0 && // If there is no destination there is nothing we can flush to. A flush will
+ // happen when we start flowing again
+ request.destination !== null) {
+ request.flushScheduled = true;
+ scheduleWork(() => {
+ // We need to existence check destination again here because it might go away
+ // in between the enqueueFlush call and the work execution
+ const destination = request.destination;
+
+ if (destination) {
+ flushCompletedQueues(request, destination);
+ } else {
+ request.flushScheduled = false;
+ }
+ });
+ }
+} // This function is intented to only be called during the pipe function for the Node builds.
+function startFlowing(request, destination) {
+ if (request.status === CLOSING) {
+ request.status = CLOSED;
+ closeWithError(destination, request.fatalError);
+ return;
+ }
+
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ if (request.destination !== null) {
+ // We're already flowing.
+ return;
+ }
+
+ request.destination = destination;
+
+ try {
+ flushCompletedQueues(request, destination);
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function stopFlowing(request) {
+ request.destination = null;
+} // This is called to early terminate a request. It puts all pending boundaries in client rendered state.
+
+function abort(request, reason) {
+ try {
+ const abortableTasks = request.abortableTasks;
+
+ if (abortableTasks.size > 0) {
+ const error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason;
+ abortableTasks.forEach(task => abortTask(task, request, error));
+ abortableTasks.clear();
+ }
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function flushResources(request) {
+ enqueueFlush(request);
+}
+function getFormState(request) {
+ return request.formState;
+}
+function getResumableState(request) {
+ return request.resumableState;
+}
+function getRenderState(request) {
+ return request.renderState;
+}
+
+function addToReplayParent(node, parentKeyPath, trackedPostpones) {
+ if (parentKeyPath === null) {
+ trackedPostpones.rootNodes.push(node);
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let parentNode = workingMap.get(parentKeyPath);
+
+ if (parentNode === undefined) {
+ parentNode = [parentKeyPath[1], parentKeyPath[2], [], null];
+ workingMap.set(parentKeyPath, parentNode);
+ addToReplayParent(parentNode, parentKeyPath[0], trackedPostpones);
+ }
+
+ parentNode[2].push(node);
+ }
+} // Returns the state of a postponed request or null if nothing was postponed.
+
+function renderToReadableStream(children, options) {
+ return new Promise((resolve, reject) => {
+ let onFatalError;
+ let onAllReady;
+ const allReady = new Promise((res, rej) => {
+ onAllReady = res;
+ onFatalError = rej;
+ });
+
+ function onShellReady() {
+ const stream = new ReadableStream({
+ type: 'direct',
+ pull: controller => {
+ // $FlowIgnore
+ startFlowing(request, controller);
+ },
+ cancel: reason => {
+ stopFlowing(request);
+ abort(request, reason);
+ }
+ }, // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
+ {
+ highWaterMark: 2048
+ }); // TODO: Move to sub-classing ReadableStream.
+
+ stream.allReady = allReady;
+ resolve(stream);
+ }
+
+ function onShellError(error) {
+ // If the shell errors the caller of `renderToReadableStream` won't have access to `allReady`.
+ // However, `allReady` will be rejected by `onFatalError` as well.
+ // So we need to catch the duplicate, uncatchable fatal error in `allReady` to prevent a `UnhandledPromiseRejection`.
+ allReady.catch(() => {});
+ reject(error);
+ }
+
+ const onHeaders = options ? options.onHeaders : undefined;
+ let onHeadersImpl;
+
+ if (onHeaders) {
+ onHeadersImpl = headersDescriptor => {
+ onHeaders(new Headers(headersDescriptor));
+ };
+ }
+
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ const request = createRequest(children, resumableState, createRenderState(resumableState, options ? options.nonce : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, onHeadersImpl, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, onAllReady, onShellReady, onShellError, onFatalError, options ? options.onPostpone : undefined, options ? options.formState : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+function renderToNodeStream() {
+ throw new Error('ReactDOMServer.renderToNodeStream(): The Node Stream API is not available ' + 'in Bun. Use ReactDOMServer.renderToReadableStream() instead.');
+}
+
+function renderToStaticNodeStream() {
+ throw new Error('ReactDOMServer.renderToStaticNodeStream(): The Node Stream API is not available ' + 'in Bun. Use ReactDOMServer.renderToReadableStream() instead.');
+}
+
+exports.renderToNodeStream = renderToNodeStream;
+exports.renderToReadableStream = renderToReadableStream;
+exports.renderToStaticNodeStream = renderToStaticNodeStream;
+exports.version = ReactVersion;
\ No newline at end of file
diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js
index a3c84b86590cf..3f40932a6c3cc 100644
--- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js
+++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js
@@ -17,7 +17,7 @@ if (process.env.NODE_ENV !== "production") {
var React = require("next/dist/compiled/react-experimental");
var ReactDOM = require('react-dom');
-var ReactVersion = '18.3.0-experimental-2983249dd-20231107';
+var ReactVersion = '18.3.0-experimental-7508dcd5c-20231108';
var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
@@ -1816,11 +1816,14 @@ var DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep tr
// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
// is set, the server will send instructions via data attributes (instead of inline scripts)
-function createRenderState(resumableState, nonce, bootstrapScriptContent, bootstrapScripts, bootstrapModules, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+function createRenderState(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
var inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const startScriptSrc = stringToPrecomputedChunk('');
+/**
+ * This escaping function is designed to work with bootstrapScriptContent and importMap only.
+ * because we know we are escaping the entire script. We can avoid for instance
+ * escaping html comment string sequences that are valid javascript as well because
+ * if there are no sebsequent '); // Since we store headers as strings we deal with their length in utf16 code units
+// rather than visual characters or the utf8 encoding that is used for most binary
+// serialization. Some common HTTP servers only allow for headers to be 4kB in length.
+// We choose a default length that is likely to be well under this already limited length however
+// pathological cases may still cause the utf-8 encoding of the headers to approach this limit.
+// It should also be noted that this maximum is a soft maximum. we have not reached the limit we will
+// allow one more header to be captured which means in practice if the limit is approached it will be exceeded
+
+const DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep track of what we've already written so we can refer back to it.
+// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
+// is set, the server will send instructions via data attributes (instead of inline scripts)
+
+function createRenderState(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+ const inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const completeSegmentData1 = stringToPrecomputedChunk('');
+const completeBoundaryData1 = stringToPrecomputedChunk('');
+const clientRenderData1 = stringToPrecomputedChunk('
+ return writeChunkAndReturn(destination, clientRenderDataEnd);
+ }
+}
+const regexForJSStringsInInstructionScripts = /[<\u2028\u2029]/g;
+
+function escapeJSStringsForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInInstructionScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const regexForJSStringsInScripts = /[&><\u2028\u2029]/g;
+
+function escapeJSObjectForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '&':
+ return '\\u0026';
+
+ case '>':
+ return '\\u003e';
+
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(''); // Tracks whether the boundary currently flushing is flushign style tags or has any
+// stylesheet dependencies not flushed in the Preamble.
+
+let currentlyRenderingBoundaryHasStylesToHoist = false; // Acts as a return value for the forEach execution of style tag flushing.
+
+let destinationHasCapacity = true;
+
+function flushStyleTagsLateForBoundary(styleQueue) {
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs;
+
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, lateStyleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ writeChunk(this, lateStyleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, lateStyleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ destinationHasCapacity = writeChunkAndReturn(this, lateStyleTagTemplateClose); // We wrote style tags for this boundary and we may need to emit a script
+ // to hoist them.
+
+ currentlyRenderingBoundaryHasStylesToHoist = true; // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function hasStylesToHoist(stylesheet) {
+ // We need to reveal boundaries with styles whenever a stylesheet it depends on is either
+ // not flushed or flushed after the preamble (shell).
+ if (stylesheet.state !== PREAMBLE) {
+ currentlyRenderingBoundaryHasStylesToHoist = true;
+ return true;
+ }
+
+ return false;
+}
+
+function writeResourcesForBoundary(destination, boundaryResources, renderState) {
+ // Reset these on each invocation, they are only safe to read in this function
+ currentlyRenderingBoundaryHasStylesToHoist = false;
+ destinationHasCapacity = true; // Flush style tags for each precedence this boundary depends on
+
+ boundaryResources.styles.forEach(flushStyleTagsLateForBoundary, destination); // Determine if this boundary has stylesheets that need to be awaited upon completion
+
+ boundaryResources.stylesheets.forEach(hasStylesToHoist);
+
+ if (currentlyRenderingBoundaryHasStylesToHoist) {
+ renderState.stylesToHoist = true;
+ }
+
+ return destinationHasCapacity;
+}
+
+function flushResource(resource) {
+ for (let i = 0; i < resource.length; i++) {
+ writeChunk(this, resource[i]);
+ }
+
+ resource.length = 0;
+}
+
+const stylesheetFlushingQueue = [];
+
+function flushStyleInPreamble(stylesheet, key, map) {
+ // We still need to encode stylesheet chunks
+ // because unlike most Hoistables and Resources we do not eagerly encode
+ // them during render. This is because if we flush late we have to send a
+ // different encoding and we don't want to encode multiple times
+ pushLinkImpl(stylesheetFlushingQueue, stylesheet.props);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ stylesheet.state = PREAMBLE;
+}
+
+const styleTagResourceOpen1 = stringToPrecomputedChunk('');
+
+function flushStylesInPreamble(styleQueue, precedence) {
+ const hasStylesheets = styleQueue.sheets.size > 0;
+ styleQueue.sheets.forEach(flushStyleInPreamble, this);
+ styleQueue.sheets.clear();
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs; // If we don't emit any stylesheets at this precedence we still need to maintain the precedence
+ // order so even if there are no rules for style tags at this precedence we emit an empty style
+ // tag with the data-precedence attribute
+
+ if (!hasStylesheets || hrefs.length) {
+ writeChunk(this, styleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, styleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ }
+
+ writeChunk(this, styleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ writeChunk(this, styleTagResourceClose); // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function preloadLateStyle(stylesheet) {
+ if (stylesheet.state === PENDING$1) {
+ stylesheet.state = PRELOADED;
+ const preloadProps = preloadAsStylePropsFromProps(stylesheet.props.href, stylesheet.props);
+ pushLinkImpl(stylesheetFlushingQueue, preloadProps);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ }
+}
+
+function preloadLateStyles(styleQueue) {
+ styleQueue.sheets.forEach(preloadLateStyle, this);
+ styleQueue.sheets.clear();
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+
+function writePreamble(destination, resumableState, renderState, willFlushAllSegments) {
+ // This function must be called exactly once on every request
+ if (!willFlushAllSegments && renderState.externalRuntimeScript) {
+ // If the root segment is incomplete due to suspended tasks
+ // (e.g. willFlushAllSegments = false) and we are using data
+ // streaming format, ensure the external runtime is sent.
+ // (User code could choose to send this even earlier by calling
+ // preinit(...), if they know they will suspend).
+ const _renderState$external = renderState.externalRuntimeScript,
+ src = _renderState$external.src,
+ chunks = _renderState$external.chunks;
+ internalPreinitScript(resumableState, renderState, src, chunks);
+ }
+
+ const htmlChunks = renderState.htmlChunks;
+ const headChunks = renderState.headChunks;
+ let i = 0; // Emit open tags before Hoistables and Resources
+
+ if (htmlChunks) {
+ // We have an to emit as part of the preamble
+ for (i = 0; i < htmlChunks.length; i++) {
+ writeChunk(destination, htmlChunks[i]);
+ }
+
+ if (headChunks) {
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } else {
+ // We did not render a head but we emitted an so we emit one now
+ writeChunk(destination, startChunkForTag('head'));
+ writeChunk(destination, endOfStartTag);
+ }
+ } else if (headChunks) {
+ // We do not have an but we do have a
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } // Emit high priority Hoistables
+
+
+ const charsetChunks = renderState.charsetChunks;
+
+ for (i = 0; i < charsetChunks.length; i++) {
+ writeChunk(destination, charsetChunks[i]);
+ }
+
+ charsetChunks.length = 0; // emit preconnect resources
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Flush unblocked stylesheets by precedence
+
+ renderState.styles.forEach(flushStylesInPreamble, destination);
+ const importMapChunks = renderState.importMapChunks;
+
+ for (i = 0; i < importMapChunks.length; i++) {
+ writeChunk(destination, importMapChunks[i]);
+ }
+
+ importMapChunks.length = 0;
+ renderState.bootstrapScripts.forEach(flushResource, destination);
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0; // Flush closing head if necessary
+
+ if (htmlChunks && headChunks === null) {
+ // We have an rendered but no rendered. We however inserted
+ // a up above so we need to emit the now. This is safe because
+ // if the main content contained the it would also have provided a
+ // . This means that all the content inside is either or
+ // invalid HTML
+ writeChunk(destination, endChunkForTag('head'));
+ }
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+function writeHoistables(destination, resumableState, renderState) {
+ let i = 0; // Emit high priority Hoistables
+ // We omit charsetChunks because we have already sent the shell and if it wasn't
+ // already sent it is too late now.
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Preload any stylesheets. these will emit in a render instruction that follows this
+ // but we want to kick off preloading as soon as possible
+
+ renderState.styles.forEach(preloadLateStyles, destination); // We only hoist importmaps that are configured through createResponse and that will
+ // always flush in the preamble. Generally we don't expect people to render them as
+ // tags when using React but if you do they are going to be treated like regular inline
+ // scripts and flush after other hoistables which is problematic
+ // bootstrap scripts should flush above script priority but these can only flush in the preamble
+ // so we elide the code here for performance
+
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0;
+}
+function writePostamble(destination, resumableState) {
+ if (resumableState.hasBody) {
+ writeChunk(destination, endChunkForTag('body'));
+ }
+
+ if (resumableState.hasHtml) {
+ writeChunk(destination, endChunkForTag('html'));
+ }
+}
+const arrayFirstOpenBracket = stringToPrecomputedChunk('[');
+const arraySubsequentOpenBracket = stringToPrecomputedChunk(',[');
+const arrayInterstitial = stringToPrecomputedChunk(',');
+const arrayCloseBracket = stringToPrecomputedChunk(']'); // This function writes a 2D array of strings to be embedded in javascript.
+// E.g.
+// [["JS_escaped_string1", "JS_escaped_string2"]]
+
+function writeStyleResourceDependenciesInJS(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInJS(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInJS(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInJS(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+}
+
+function writeStyleResourceDependencyInJS(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedPrecedence)));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInJS(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInJS(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeName)));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeValue)));
+} // This function writes a 2D array of strings to be embedded in an attribute
+// value and read with JSON.parse in ReactDOMServerExternalRuntime.js
+// E.g.
+// [["JSON_escaped_string1", "JSON_escaped_string2"]]
+
+
+function writeStyleResourceDependenciesInAttr(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInAttr(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInAttr(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInAttr(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+}
+
+function writeStyleResourceDependencyInAttr(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedPrecedence))));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInAttr(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInAttr(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeName))));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeValue))));
+}
+/**
+ * Resources
+ */
+
+
+const PENDING$1 = 0;
+const PRELOADED = 1;
+const PREAMBLE = 2;
+const LATE = 3;
+function createBoundaryResources() {
+ return {
+ styles: new Set(),
+ stylesheets: new Set()
+ };
+}
+function setCurrentlyRenderingBoundaryResourcesTarget(renderState, boundaryResources) {
+ renderState.boundaryResources = boundaryResources;
+}
+
+function getResourceKey(href) {
+ return href;
+}
+
+function getImageResourceKey(href, imageSrcSet, imageSizes) {
+ if (imageSrcSet) {
+ return imageSrcSet + '\n' + (imageSizes || '');
+ }
+
+ return href;
+}
+
+function prefetchDNS(href) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const key = getResourceKey(href);
+
+ if (!resumableState.dnsResources.hasOwnProperty(key)) {
+ resumableState.dnsResources[key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPrefetchDNSAsHeader(href), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this as resettable in case we are prerendering and postpone in the Shell
+ renderState.resets.dns[key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ // Encode as element
+ const resource = [];
+ pushLinkImpl(resource, {
+ href,
+ rel: 'dns-prefetch'
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preconnect(href, crossOrigin) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const bucket = crossOrigin === 'use-credentials' ? 'credentials' : typeof crossOrigin === 'string' ? 'anonymous' : 'default';
+ const key = getResourceKey(href);
+
+ if (!resumableState.connectResources[bucket].hasOwnProperty(key)) {
+ resumableState.connectResources[bucket][key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreconnectAsHeader(href, crossOrigin), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this in resettableState in case we are prerending and postpone in the Shell
+ renderState.resets.connect[bucket][key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ const resource = [];
+ pushLinkImpl(resource, {
+ rel: 'preconnect',
+ href,
+ crossOrigin
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preload(href, as, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (as && href) {
+ switch (as) {
+ case 'image':
+ {
+ let imageSrcSet, imageSizes, fetchPriority;
+
+ if (options) {
+ imageSrcSet = options.imageSrcSet;
+ imageSizes = options.imageSizes;
+ fetchPriority = options.fetchPriority;
+ }
+
+ const key = getImageResourceKey(href, imageSrcSet, imageSizes);
+
+ if (resumableState.imageResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resumableState.imageResources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && fetchPriority === 'high' && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit a preload as a header so we
+ // track this to make sure we don't reset it.
+ renderState.resets.image[key] = PRELOAD_NO_CREDS;
+
+ if (headers.highImagePreloads) {
+ headers.highImagePreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.highImagePreloads += header;
+ } else {
+ // If we don't have headers to write to we have to encode as elements to flush in the head
+ // When we have imageSrcSet the browser probably cannot load the right version from headers
+ // (this should be verified by testing). For now we assume these need to go in the head
+ // as elements even if headers are available.
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ // There is a bug in Safari where imageSrcSet is not respected on preload links
+ // so we omit the href here if we have imageSrcSet b/c safari will load the wrong image.
+ // This harms older browers that do not support imageSrcSet by making their preloads not work
+ // but this population is shrinking fast and is already small so we accept this tradeoff.
+ href: imageSrcSet ? undefined : href,
+ as
+ }, options));
+
+ if (fetchPriority === 'high') {
+ renderState.highImagePreloads.add(resource);
+ } else {
+ renderState.bulkPreloads.add(resource); // Stash the resource in case we need to promote it to higher priority
+ // when an img tag is rendered
+
+ renderState.preloads.images.set(key, resource);
+ }
+ }
+
+ break;
+ }
+
+ case 'style':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.styleResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.styleResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.stylesheets.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ break;
+ }
+
+ case 'script':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.scriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ renderState.preloads.scripts.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.scriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ break;
+ }
+
+ default:
+ {
+ const key = getResourceKey(href);
+ const hasAsType = resumableState.unknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.unknownResources[as] = resources;
+ }
+
+ resources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && as === 'font' && ( // We compute the header here because we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit this preload so we
+ // track it here to prevent it from being reset.
+ renderState.resets.font[key] = PRELOAD_NO_CREDS;
+
+ if (headers.fontPreloads) {
+ headers.fontPreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.fontPreloads += header;
+ } else {
+ // We either don't have headers or we are preloading something that does
+ // not warrant elevated priority so we encode as an element.
+ const resource = [];
+
+ const props = assign({
+ rel: 'preload',
+ href,
+ as
+ }, options);
+
+ pushLinkImpl(resource, props);
+
+ switch (as) {
+ case 'font':
+ renderState.fontPreloads.add(resource);
+ break;
+ // intentional fall through
+
+ default:
+ renderState.bulkPreloads.add(resource);
+ }
+ }
+ }
+ } // If we got this far we created a new resource
+
+
+ flushResources(request);
+ }
+}
+
+function preloadModule(href, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ const key = getResourceKey(href);
+ const as = options && typeof options.as === 'string' ? options.as : 'script';
+ let resource;
+
+ switch (as) {
+ case 'script':
+ {
+ if (resumableState.moduleScriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resource = [];
+ resumableState.moduleScriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.moduleScripts.set(key, resource);
+ break;
+ }
+
+ default:
+ {
+ const hasAsType = resumableState.moduleUnknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.moduleUnknownResources[as] = resources;
+ }
+
+ resource = [];
+ resources[key] = PRELOAD_NO_CREDS;
+ }
+ }
+
+ pushLinkImpl(resource, assign({
+ rel: 'modulepreload',
+ href
+ }, options));
+ renderState.bulkPreloads.add(resource); // If we got this far we created a new resource
+
+ flushResources(request);
+ }
+}
+
+function preinitStyle(href, precedence, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ precedence = precedence || 'default';
+ const key = getResourceKey(href);
+ let styleQueue = renderState.styles.get(precedence);
+ const hasKey = resumableState.styleResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.styleResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.styleResources[key] = EXISTS; // If this is the first time we've encountered this precedence we need
+ // to create a StyleQueue
+
+ if (!styleQueue) {
+ styleQueue = {
+ precedence: stringToChunk(escapeTextForBrowser(precedence)),
+ rules: [],
+ hrefs: [],
+ sheets: new Map()
+ };
+ renderState.styles.set(precedence, styleQueue);
+ }
+
+ const resource = {
+ state: PENDING$1,
+ props: assign({
+ rel: 'stylesheet',
+ href,
+ 'data-precedence': precedence
+ }, options)
+ };
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(resource.props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.stylesheets.get(key);
+
+ if (preloadResource && preloadResource.length > 0) {
+ // The Preload for this resource was created in this render pass and has not flushed yet so
+ // we need to clear it to avoid it flushing.
+ preloadResource.length = 0;
+ } else {
+ // Either the preload resource from this render already flushed in this render pass
+ // or the preload flushed in a prior pass (prerender). In either case we need to mark
+ // this resource as already having been preloaded.
+ resource.state = PRELOADED;
+ }
+ } // We add the newly created resource to our StyleQueue and if necessary
+ // track the resource with the currently rendering boundary
+
+
+ styleQueue.sheets.set(key, resource); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+ }
+}
+
+function preinitScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.scriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.scriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.scriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.scripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+}
+
+function preinitModuleScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.moduleScriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.moduleScriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.moduleScriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ type: 'module',
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.moduleScripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+} // This function is only safe to call at Request start time since it assumes
+// that each module has not already been preloaded. If we find a need to preload
+// scripts at any other point in time we will need to check whether the preload
+// already exists and not assume it
+
+
+function preloadBootstrapScriptOrModule(resumableState, renderState, href, props) {
+
+ const key = getResourceKey(href);
+ // used to preinit the resource. If a script can be preinited then it shouldn't
+ // be a bootstrap script/module and if it is a bootstrap script/module then it
+ // must not be safe to emit early. To avoid possibly allowing for preinits of
+ // bootstrap scripts/modules we occlude these keys.
+
+
+ resumableState.scriptResources[key] = EXISTS;
+ resumableState.moduleScriptResources[key] = EXISTS;
+ const resource = [];
+ pushLinkImpl(resource, props);
+ renderState.bootstrapScripts.add(resource);
+}
+
+function internalPreinitScript(resumableState, renderState, src, chunks) {
+ const key = getResourceKey(src);
+
+ if (!resumableState.scriptResources.hasOwnProperty(key)) {
+ const resource = chunks;
+ resumableState.scriptResources[key] = EXISTS;
+ renderState.scripts.add(resource);
+ }
+
+ return;
+}
+
+function preloadAsStylePropsFromProps(href, props) {
+ return {
+ rel: 'preload',
+ as: 'style',
+ href: href,
+ crossOrigin: props.crossOrigin,
+ fetchPriority: props.fetchPriority,
+ integrity: props.integrity,
+ media: props.media,
+ hrefLang: props.hrefLang,
+ referrerPolicy: props.referrerPolicy
+ };
+}
+
+function stylesheetPropsFromRawProps(rawProps) {
+ return assign({}, rawProps, {
+ 'data-precedence': rawProps.precedence,
+ precedence: null
+ });
+}
+
+function adoptPreloadCredentials(target, preloadState) {
+ if (target.crossOrigin == null) target.crossOrigin = preloadState[0];
+ if (target.integrity == null) target.integrity = preloadState[1];
+}
+
+function getPrefetchDNSAsHeader(href) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ return "<" + escapedHref + ">; rel=dns-prefetch";
+}
+
+function getPreconnectAsHeader(href, crossOrigin) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ let value = "<" + escapedHref + ">; rel=preconnect";
+
+ if (typeof crossOrigin === 'string') {
+ const escapedCrossOrigin = escapeStringForLinkHeaderQuotedParamValueContext(crossOrigin);
+ value += "; crossorigin=\"" + escapedCrossOrigin + "\"";
+ }
+
+ return value;
+}
+
+function getPreloadAsHeader(href, as, params) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ const escapedAs = escapeStringForLinkHeaderQuotedParamValueContext(as);
+ let value = "<" + escapedHref + ">; rel=preload; as=\"" + escapedAs + "\"";
+
+ for (const paramName in params) {
+ if (hasOwnProperty.call(params, paramName)) {
+ const paramValue = params[paramName];
+
+ if (typeof paramValue === 'string') {
+ value += "; " + paramName.toLowerCase() + "=\"" + escapeStringForLinkHeaderQuotedParamValueContext(paramValue) + "\"";
+ }
+ }
+ }
+
+ return value;
+}
+
+function getStylesheetPreloadAsHeader(stylesheet) {
+ const props = stylesheet.props;
+ const preloadOptions = {
+ crossOrigin: props.crossOrigin,
+ integrity: props.integrity,
+ nonce: props.nonce,
+ type: props.type,
+ fetchPriority: props.fetchPriority,
+ referrerPolicy: props.referrerPolicy,
+ media: props.media
+ };
+ return getPreloadAsHeader(props.href, 'style', preloadOptions);
+} // This escaping function is only safe to use for href values being written into
+// a "Link" header in between `<` and `>` characters. The primary concern with the href is
+// to escape the bounding characters as well as new lines. This is unsafe to use in any other
+// context
+
+
+const regexForHrefInLinkHeaderURLContext = /[<>\r\n]/g;
+
+function escapeHrefForLinkHeaderURLContext(hrefInput) {
+
+ const coercedHref = '' + hrefInput;
+ return coercedHref.replace(regexForHrefInLinkHeaderURLContext, escapeHrefForLinkHeaderURLContextReplacer);
+}
+
+function escapeHrefForLinkHeaderURLContextReplacer(match) {
+ switch (match) {
+ case '<':
+ return '%3C';
+
+ case '>':
+ return '%3E';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+} // This escaping function is only safe to use for quoted param values in an HTTP header.
+// It is unsafe to use for any value not inside quote marks in parater value position.
+
+
+const regexForLinkHeaderQuotedParamValueContext = /["';,\r\n]/g;
+
+function escapeStringForLinkHeaderQuotedParamValueContext(value, name) {
+
+ const coerced = '' + value;
+ return coerced.replace(regexForLinkHeaderQuotedParamValueContext, escapeStringForLinkHeaderQuotedParamValueContextReplacer);
+}
+
+function escapeStringForLinkHeaderQuotedParamValueContextReplacer(match) {
+ switch (match) {
+ case '"':
+ return '%22';
+
+ case "'":
+ return '%27';
+
+ case ';':
+ return '%3B';
+
+ case ',':
+ return '%2C';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+}
+
+function hoistStyleQueueDependency(styleQueue) {
+ this.styles.add(styleQueue);
+}
+
+function hoistStylesheetDependency(stylesheet) {
+ this.stylesheets.add(stylesheet);
+}
+
+function hoistResources(renderState, source) {
+ const currentBoundaryResources = renderState.boundaryResources;
+
+ if (currentBoundaryResources) {
+ source.styles.forEach(hoistStyleQueueDependency, currentBoundaryResources);
+ source.stylesheets.forEach(hoistStylesheetDependency, currentBoundaryResources);
+ }
+} // This function is called at various times depending on whether we are rendering
+// or prerendering. In this implementation we only actually emit headers once and
+// subsequent calls are ignored. We track whether the request has a completed shell
+// to determine whether we will follow headers with a flush including stylesheets.
+// In the context of prerrender we don't have a completed shell when the request finishes
+// with a postpone in the shell. In the context of a render we don't have a completed shell
+// if this is called before the shell finishes rendering which usually will happen anytime
+// anything suspends in the shell.
+
+function emitEarlyPreloads(renderState, resumableState, shellComplete) {
+ const onHeaders = renderState.onHeaders;
+
+ if (onHeaders) {
+ const headers = renderState.headers;
+
+ if (headers) {
+ let linkHeader = headers.preconnects;
+
+ if (headers.fontPreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.fontPreloads;
+ }
+
+ if (headers.highImagePreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.highImagePreloads;
+ }
+
+ if (!shellComplete) {
+ // We use raw iterators because we want to be able to halt iteration
+ // We could refactor renderState to store these dually in arrays to
+ // make this more efficient at the cost of additional memory and
+ // write overhead. However this code only runs once per request so
+ // for now I consider this sufficient.
+ const queueIter = renderState.styles.values();
+
+ outer: for (let queueStep = queueIter.next(); headers.remainingCapacity > 0 && !queueStep.done; queueStep = queueIter.next()) {
+ const sheets = queueStep.value.sheets;
+ const sheetIter = sheets.values();
+
+ for (let sheetStep = sheetIter.next(); headers.remainingCapacity > 0 && !sheetStep.done; sheetStep = sheetIter.next()) {
+ const sheet = sheetStep.value;
+ const props = sheet.props;
+ const key = getResourceKey(props.href);
+ const header = getStylesheetPreloadAsHeader(sheet); // We mutate the capacity b/c we don't want to keep checking if later headers will fit.
+ // This means that a particularly long header might close out the header queue where later
+ // headers could still fit. We could in the future alter the behavior here based on prerender vs render
+ // since during prerender we aren't as concerned with pure runtime performance.
+
+ if ((headers.remainingCapacity -= header.length) >= 2) {
+ renderState.resets.style[key] = PRELOAD_NO_CREDS;
+
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += header; // We already track that the resource exists in resumableState however
+ // if the resumableState resets because we postponed in the shell
+ // which is what is happening in this branch if we are prerendering
+ // then we will end up resetting the resumableState. When it resets we
+ // want to record the fact that this stylesheet was already preloaded
+
+ renderState.resets.style[key] = typeof props.crossOrigin === 'string' || typeof props.integrity === 'string' ? [props.crossOrigin, props.integrity] : PRELOAD_NO_CREDS;
+ } else {
+ break outer;
+ }
+ }
+ }
+ }
+
+ if (linkHeader) {
+ onHeaders({
+ Link: linkHeader
+ });
+ } else {
+ // We still call this with no headers because a user may be using it as a signal that
+ // it React will not provide any headers
+ onHeaders({});
+ }
+
+ renderState.headers = null;
+ return;
+ }
+ }
+}
+const NotPendingTransition = NotPending;
+
+const supportsRequestStorage = typeof AsyncLocalStorage === 'function';
+const requestStorage = supportsRequestStorage ? new AsyncLocalStorage() : null;
+
+// ATTENTION
+// When adding new symbols to this file,
+// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
+// The Symbol used to tag the ReactElement-like types.
+const REACT_ELEMENT_TYPE = Symbol.for('react.element');
+const REACT_PORTAL_TYPE = Symbol.for('react.portal');
+const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
+const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
+const REACT_PROFILER_TYPE = Symbol.for('react.profiler');
+const REACT_PROVIDER_TYPE = Symbol.for('react.provider');
+const REACT_CONTEXT_TYPE = Symbol.for('react.context');
+const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
+const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
+const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
+const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
+const REACT_MEMO_TYPE = Symbol.for('react.memo');
+const REACT_LAZY_TYPE = Symbol.for('react.lazy');
+const REACT_SCOPE_TYPE = Symbol.for('react.scope');
+const REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');
+const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
+const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');
+const REACT_CACHE_TYPE = Symbol.for('react.cache');
+const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value');
+const REACT_MEMO_CACHE_SENTINEL = Symbol.for('react.memo_cache_sentinel');
+const REACT_POSTPONE_TYPE = Symbol.for('react.postpone');
+const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
+const FAUX_ITERATOR_SYMBOL = '@@iterator';
+function getIteratorFn(maybeIterable) {
+ if (maybeIterable === null || typeof maybeIterable !== 'object') {
+ return null;
+ }
+
+ const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
+
+ if (typeof maybeIterator === 'function') {
+ return maybeIterator;
+ }
+
+ return null;
+}
+
+function getWrappedName(outerType, innerType, wrapperName) {
+ const displayName = outerType.displayName;
+
+ if (displayName) {
+ return displayName;
+ }
+
+ const functionName = innerType.displayName || innerType.name || '';
+ return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName;
+} // Keep in sync with react-reconciler/getComponentNameFromFiber
+
+
+function getContextName(type) {
+ return type.displayName || 'Context';
+} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+
+
+function getComponentNameFromType(type) {
+ if (type == null) {
+ // Host root, text node or just invalid type.
+ return null;
+ }
+
+ if (typeof type === 'function') {
+ return type.displayName || type.name || null;
+ }
+
+ if (typeof type === 'string') {
+ return type;
+ }
+
+ switch (type) {
+ case REACT_FRAGMENT_TYPE:
+ return 'Fragment';
+
+ case REACT_PORTAL_TYPE:
+ return 'Portal';
+
+ case REACT_PROFILER_TYPE:
+ return 'Profiler';
+
+ case REACT_STRICT_MODE_TYPE:
+ return 'StrictMode';
+
+ case REACT_SUSPENSE_TYPE:
+ return 'Suspense';
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ return 'SuspenseList';
+
+ case REACT_CACHE_TYPE:
+ {
+ return 'Cache';
+ }
+
+ }
+
+ if (typeof type === 'object') {
+ switch (type.$$typeof) {
+ case REACT_CONTEXT_TYPE:
+ const context = type;
+ return getContextName(context) + '.Consumer';
+
+ case REACT_PROVIDER_TYPE:
+ const provider = type;
+ return getContextName(provider._context) + '.Provider';
+
+ case REACT_FORWARD_REF_TYPE:
+ return getWrappedName(type, type.render, 'ForwardRef');
+
+ case REACT_MEMO_TYPE:
+ const outerName = type.displayName || null;
+
+ if (outerName !== null) {
+ return outerName;
+ }
+
+ return getComponentNameFromType(type.type) || 'Memo';
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyComponent = type;
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+
+ try {
+ return getComponentNameFromType(init(payload));
+ } catch (x) {
+ return null;
+ }
+ }
+
+ case REACT_SERVER_CONTEXT_TYPE:
+ {
+ const context2 = type;
+ return (context2.displayName || context2._globalName) + '.Provider';
+ }
+
+ }
+ }
+
+ return null;
+}
+
+const emptyContextObject = {};
+
+function getMaskedContext(type, unmaskedContext) {
+ {
+ const contextTypes = type.contextTypes;
+
+ if (!contextTypes) {
+ return emptyContextObject;
+ }
+
+ const context = {};
+
+ for (const key in contextTypes) {
+ context[key] = unmaskedContext[key];
+ }
+
+ return context;
+ }
+}
+function processChildContext(instance, type, parentContext, childContextTypes) {
+ {
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
+ if (typeof instance.getChildContext !== 'function') {
+
+ return parentContext;
+ }
+
+ const childContext = instance.getChildContext();
+
+ for (const contextKey in childContext) {
+ if (!(contextKey in childContextTypes)) {
+ throw new Error((getComponentNameFromType(type) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes.");
+ }
+ }
+
+ return assign({}, parentContext, childContext);
+ }
+}
+
+// Forming a reverse tree.
+// The structure of a context snapshot is an implementation of this file.
+// Currently, it's implemented as tracking the current active node.
+
+
+const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
+// This global (actually thread local) state represents what state all those "current",
+// fields are currently in.
+
+let currentActiveSnapshot = null;
+
+function popNode(prev) {
+ {
+ prev.context._currentValue = prev.parentValue;
+ }
+}
+
+function pushNode(next) {
+ {
+ next.context._currentValue = next.value;
+ }
+}
+
+function popToNearestCommonAncestor(prev, next) {
+ if (prev === next) ; else {
+ popNode(prev);
+ const parentPrev = prev.parent;
+ const parentNext = next.parent;
+
+ if (parentPrev === null) {
+ if (parentNext !== null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+ } else {
+ if (parentNext === null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+
+ popToNearestCommonAncestor(parentPrev, parentNext);
+ } // On the way back, we push the new ones that weren't common.
+
+
+ pushNode(next);
+ }
+}
+
+function popAllPrevious(prev) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev !== null) {
+ popAllPrevious(parentPrev);
+ }
+}
+
+function pushAllNext(next) {
+ const parentNext = next.parent;
+
+ if (parentNext !== null) {
+ pushAllNext(parentNext);
+ }
+
+ pushNode(next);
+}
+
+function popPreviousToCommonLevel(prev, next) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (parentPrev.depth === next.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(parentPrev, next);
+ } else {
+ // We must still be deeper.
+ popPreviousToCommonLevel(parentPrev, next);
+ }
+}
+
+function popNextToCommonLevel(prev, next) {
+ const parentNext = next.parent;
+
+ if (parentNext === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (prev.depth === parentNext.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(prev, parentNext);
+ } else {
+ // We must still be deeper.
+ popNextToCommonLevel(prev, parentNext);
+ }
+
+ pushNode(next);
+} // Perform context switching to the new snapshot.
+// To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
+// updating all the context's current values. That way reads, always just read the current value.
+// At the cost of updating contexts even if they're never read by this subtree.
+
+
+function switchContext(newSnapshot) {
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
+ // We also need to update any new contexts that are now on the stack with the deepest value.
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
+ // for that. Therefore this algorithm is recursive.
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
+ // 3) Then we reapply new contexts on the way back up the stack.
+ const prev = currentActiveSnapshot;
+ const next = newSnapshot;
+
+ if (prev !== next) {
+ if (prev === null) {
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
+ pushAllNext(next);
+ } else if (next === null) {
+ popAllPrevious(prev);
+ } else if (prev.depth === next.depth) {
+ popToNearestCommonAncestor(prev, next);
+ } else if (prev.depth > next.depth) {
+ popPreviousToCommonLevel(prev, next);
+ } else {
+ popNextToCommonLevel(prev, next);
+ }
+
+ currentActiveSnapshot = next;
+ }
+}
+function pushProvider(context, nextValue) {
+ let prevValue;
+
+ {
+ prevValue = context._currentValue;
+ context._currentValue = nextValue;
+ }
+
+ const prevNode = currentActiveSnapshot;
+ const newNode = {
+ parent: prevNode,
+ depth: prevNode === null ? 0 : prevNode.depth + 1,
+ context: context,
+ parentValue: prevValue,
+ value: nextValue
+ };
+ currentActiveSnapshot = newNode;
+ return newNode;
+}
+function popProvider(context) {
+ const prevSnapshot = currentActiveSnapshot;
+
+ if (prevSnapshot === null) {
+ throw new Error('Tried to pop a Context at the root of the app. This is a bug in React.');
+ }
+
+ {
+ const value = prevSnapshot.parentValue;
+
+ if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) {
+ prevSnapshot.context._currentValue = prevSnapshot.context._defaultValue;
+ } else {
+ prevSnapshot.context._currentValue = value;
+ }
+ }
+
+ return currentActiveSnapshot = prevSnapshot.parent;
+}
+function getActiveContext() {
+ return currentActiveSnapshot;
+}
+function readContext$1(context) {
+ const value = context._currentValue ;
+ return value;
+}
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ *
+ * Note that this module is currently shared and assumed to be stateless.
+ * If this becomes an actual Map, that will break.
+ */
+function get(key) {
+ return key._reactInternals;
+}
+function set(key, value) {
+ key._reactInternals = value;
+}
+
+const classComponentUpdater = {
+ isMounted(inst) {
+ return false;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueSetState(inst, payload, callback) {
+ const internals = get(inst);
+
+ if (internals.queue === null) ; else {
+ internals.queue.push(payload);
+ }
+ },
+
+ enqueueReplaceState(inst, payload, callback) {
+ const internals = get(inst);
+ internals.replace = true;
+ internals.queue = [payload];
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueForceUpdate(inst, callback) {
+ }
+
+};
+
+function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) {
+ const partialState = getDerivedStateFromProps(nextProps, prevState);
+
+
+ const newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);
+ return newState;
+}
+
+function constructClassInstance(ctor, props, maskedLegacyContext) {
+ let context = emptyContextObject;
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ context = readContext$1(contextType);
+ } else {
+ context = maskedLegacyContext;
+ }
+
+ const instance = new ctor(props, context);
+
+ return instance;
+}
+
+function callComponentWillMount(type, instance) {
+ const oldState = instance.state;
+
+ if (typeof instance.componentWillMount === 'function') {
+
+ instance.componentWillMount();
+ }
+
+ if (typeof instance.UNSAFE_componentWillMount === 'function') {
+ instance.UNSAFE_componentWillMount();
+ }
+
+ if (oldState !== instance.state) {
+
+ classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
+ }
+}
+
+function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) {
+ if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
+ const oldQueue = internalInstance.queue;
+ const oldReplace = internalInstance.replace;
+ internalInstance.queue = null;
+ internalInstance.replace = false;
+
+ if (oldReplace && oldQueue.length === 1) {
+ inst.state = oldQueue[0];
+ } else {
+ let nextState = oldReplace ? oldQueue[0] : inst.state;
+ let dontMutate = true;
+
+ for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
+ const partial = oldQueue[i];
+ const partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial;
+
+ if (partialState != null) {
+ if (dontMutate) {
+ dontMutate = false;
+ nextState = assign({}, nextState, partialState);
+ } else {
+ assign(nextState, partialState);
+ }
+ }
+ }
+
+ inst.state = nextState;
+ }
+ } else {
+ internalInstance.queue = null;
+ }
+} // Invokes the mount life-cycles on a previously never rendered instance.
+
+
+function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) {
+
+ const initialState = instance.state !== undefined ? instance.state : null;
+ instance.updater = classComponentUpdater;
+ instance.props = newProps;
+ instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway.
+ // The internal instance will be used to manage updates that happen during this mount.
+
+ const internalInstance = {
+ queue: [],
+ replace: false
+ };
+ set(instance, internalInstance);
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ instance.context = readContext$1(contextType);
+ } else {
+ instance.context = maskedLegacyContext;
+ }
+
+ const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
+
+ if (typeof getDerivedStateFromProps === 'function') {
+ instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps);
+ } // In order to support react-lifecycles-compat polyfilled components,
+ // Unsafe lifecycles should not be invoked for components using the new APIs.
+
+
+ if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
+ callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's
+ // process them now.
+
+ processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext);
+ }
+}
+
+// Ids are base 32 strings whose binary representation corresponds to the
+// position of a node in a tree.
+// Every time the tree forks into multiple children, we add additional bits to
+// the left of the sequence that represent the position of the child within the
+// current level of children.
+//
+// 00101 00010001011010101
+// ╰─┬─╯ ╰───────┬───────╯
+// Fork 5 of 20 Parent id
+//
+// The leading 0s are important. In the above example, you only need 3 bits to
+// represent slot 5. However, you need 5 bits to represent all the forks at
+// the current level, so we must account for the empty bits at the end.
+//
+// For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise,
+// the zeroth id at a level would be indistinguishable from its parent.
+//
+// If a node has only one child, and does not materialize an id (i.e. does not
+// contain a useId hook), then we don't need to allocate any space in the
+// sequence. It's treated as a transparent indirection. For example, these two
+// trees produce the same ids:
+//
+// <> <>
+//
+//
+// >
+//
+// >
+//
+// However, we cannot skip any node that materializes an id. Otherwise, a parent
+// id that does not fork would be indistinguishable from its child id. For
+// example, this tree does not fork, but the parent and child must have
+// different ids.
+//
+//
+//
+//
+//
+// To handle this scenario, every time we materialize an id, we allocate a
+// new level with a single slot. You can think of this as a fork with only one
+// prong, or an array of children with length 1.
+//
+// It's possible for the size of the sequence to exceed 32 bits, the max
+// size for bitwise operations. When this happens, we make more room by
+// converting the right part of the id to a string and storing it in an overflow
+// variable. We use a base 32 string representation, because 32 is the largest
+// power of 2 that is supported by toString(). We want the base to be large so
+// that the resulting ids are compact, and we want the base to be a power of 2
+// because every log2(base) bits corresponds to a single character, i.e. every
+// log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without
+// affecting the final result.
+const emptyTreeContext = {
+ id: 1,
+ overflow: ''
+};
+function getTreeId(context) {
+ const overflow = context.overflow;
+ const idWithLeadingBit = context.id;
+ const id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);
+ return id.toString(32) + overflow;
+}
+function pushTreeContext(baseContext, totalChildren, index) {
+ const baseIdWithLeadingBit = baseContext.id;
+ const baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part
+ // of the id; we use it to account for leading 0s.
+
+ const baseLength = getBitLength(baseIdWithLeadingBit) - 1;
+ const baseId = baseIdWithLeadingBit & ~(1 << baseLength);
+ const slot = index + 1;
+ const length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into
+ // consideration the leading 1 we use to mark the end of the sequence.
+
+ if (length > 30) {
+ // We overflowed the bitwise-safe range. Fall back to slower algorithm.
+ // This branch assumes the length of the base id is greater than 5; it won't
+ // work for smaller ids, because you need 5 bits per character.
+ //
+ // We encode the id in multiple steps: first the base id, then the
+ // remaining digits.
+ //
+ // Each 5 bit sequence corresponds to a single base 32 character. So for
+ // example, if the current id is 23 bits long, we can convert 20 of those
+ // bits into a string of 4 characters, with 3 bits left over.
+ //
+ // First calculate how many bits in the base id represent a complete
+ // sequence of characters.
+ const numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.
+
+ const newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.
+
+ const newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.
+
+ const restOfBaseId = baseId >> numberOfOverflowBits;
+ const restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because
+ // we made more room, this time it won't overflow.
+
+ const restOfLength = getBitLength(totalChildren) + restOfBaseLength;
+ const restOfNewBits = slot << restOfBaseLength;
+ const id = restOfNewBits | restOfBaseId;
+ const overflow = newOverflow + baseOverflow;
+ return {
+ id: 1 << restOfLength | id,
+ overflow
+ };
+ } else {
+ // Normal path
+ const newBits = slot << baseLength;
+ const id = newBits | baseId;
+ const overflow = baseOverflow;
+ return {
+ id: 1 << length | id,
+ overflow
+ };
+ }
+}
+
+function getBitLength(number) {
+ return 32 - clz32(number);
+}
+
+function getLeadingBit(id) {
+ return 1 << getBitLength(id) - 1;
+} // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback.
+
+
+const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.
+// Based on:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+const log = Math.log;
+const LN2 = Math.LN2;
+
+function clz32Fallback(x) {
+ const asUint = x >>> 0;
+
+ if (asUint === 0) {
+ return 32;
+ }
+
+ return 31 - (log(asUint) / LN2 | 0) | 0;
+}
+
+// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
+// changes to one module should be reflected in the others.
+// TODO: Rename this module and the corresponding Fiber one to "Thenable"
+// instead of "Wakeable". Or some other more appropriate name.
+// An error that is thrown (e.g. by `use`) to trigger Suspense. If we
+// detect this is caught by userspace, we'll log a warning in development.
+const SuspenseException = new Error("Suspense Exception: This is not a real error! It's an implementation " + 'detail of `use` to interrupt the current render. You must either ' + 'rethrow it immediately, or move the `use` call outside of the ' + '`try/catch` block. Capturing without rethrowing will lead to ' + 'unexpected behavior.\n\n' + 'To handle async errors, wrap your component in an error boundary, or ' + "call the promise's `.catch` method and pass the result to `use`");
+function createThenableState() {
+ // The ThenableState is created the first time a component suspends. If it
+ // suspends again, we'll reuse the same state.
+ return [];
+}
+
+function noop$2() {}
+
+function trackUsedThenable(thenableState, thenable, index) {
+ const previous = thenableState[index];
+
+ if (previous === undefined) {
+ thenableState.push(thenable);
+ } else {
+ if (previous !== thenable) {
+ // Reuse the previous thenable, and drop the new one. We can assume
+ // they represent the same value, because components are idempotent.
+ // Avoid an unhandled rejection errors for the Promises that we'll
+ // intentionally ignore.
+ thenable.then(noop$2, noop$2);
+ thenable = previous;
+ }
+ } // We use an expando to track the status and result of a thenable so that we
+ // can synchronously unwrap the value. Think of this as an extension of the
+ // Promise API, or a custom interface that is a superset of Thenable.
+ //
+ // If the thenable doesn't have a status, set it to "pending" and attach
+ // a listener that will update its status and result when it resolves.
+
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledValue = thenable.value;
+ return fulfilledValue;
+ }
+
+ case 'rejected':
+ {
+ const rejectedError = thenable.reason;
+ throw rejectedError;
+ }
+
+ default:
+ {
+ if (typeof thenable.status === 'string') ; else {
+ const pendingThenable = thenable;
+ pendingThenable.status = 'pending';
+ pendingThenable.then(fulfilledValue => {
+ if (thenable.status === 'pending') {
+ const fulfilledThenable = thenable;
+ fulfilledThenable.status = 'fulfilled';
+ fulfilledThenable.value = fulfilledValue;
+ }
+ }, error => {
+ if (thenable.status === 'pending') {
+ const rejectedThenable = thenable;
+ rejectedThenable.status = 'rejected';
+ rejectedThenable.reason = error;
+ }
+ }); // Check one more time in case the thenable resolved synchronously
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledThenable = thenable;
+ return fulfilledThenable.value;
+ }
+
+ case 'rejected':
+ {
+ const rejectedThenable = thenable;
+ throw rejectedThenable.reason;
+ }
+ }
+ } // Suspend.
+ //
+ // Throwing here is an implementation detail that allows us to unwind the
+ // call stack. But we shouldn't allow it to leak into userspace. Throw an
+ // opaque placeholder value instead of the actual thenable. If it doesn't
+ // get captured by the work loop, log a warning, because that means
+ // something in userspace must have caught it.
+
+
+ suspendedThenable = thenable;
+ throw SuspenseException;
+ }
+ }
+} // This is used to track the actual thenable that suspended so it can be
+// passed to the rest of the Suspense implementation — which, for historical
+// reasons, expects to receive a thenable.
+
+let suspendedThenable = null;
+function getSuspendedThenable() {
+ // This is called right after `use` suspends by throwing an exception. `use`
+ // throws an opaque value instead of the thenable itself so that it can't be
+ // caught in userspace. Then the work loop accesses the actual thenable using
+ // this function.
+ if (suspendedThenable === null) {
+ throw new Error('Expected a suspended thenable. This is a bug in React. Please file ' + 'an issue.');
+ }
+
+ const thenable = suspendedThenable;
+ suspendedThenable = null;
+ return thenable;
+}
+
+/**
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+ */
+function is(x, y) {
+ return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
+ ;
+}
+
+const objectIs = // $FlowFixMe[method-unbinding]
+typeof Object.is === 'function' ? Object.is : is;
+
+let currentlyRenderingComponent = null;
+let currentlyRenderingTask = null;
+let currentlyRenderingRequest = null;
+let currentlyRenderingKeyPath = null;
+let firstWorkInProgressHook = null;
+let workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook
+
+let isReRender = false; // Whether an update was scheduled during the currently executing render pass.
+
+let didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component
+
+let localIdCounter = 0; // Chunks that should be pushed to the stream once the component
+// finishes rendering.
+// Counts the number of useFormState calls in this component
+
+let formStateCounter = 0; // The index of the useFormState hook that matches the one passed in at the
+// root during an MPA navigation, if any.
+
+let formStateMatchingIndex = -1; // Counts the number of use(thenable) calls in this component
+
+let thenableIndexCounter = 0;
+let thenableState = null; // Lazily created map of render-phase updates
+
+let renderPhaseUpdates = null; // Counter to prevent infinite loops.
+
+let numberOfReRenders = 0;
+const RE_RENDER_LIMIT = 25;
+
+function resolveCurrentlyRenderingComponent() {
+ if (currentlyRenderingComponent === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + '2. You might be breaking the Rules of Hooks\n' + '3. You might have more than one copy of React in the same app\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.');
+ }
+
+ return currentlyRenderingComponent;
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+
+ return false;
+ }
+
+
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ if (objectIs(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+function createHook() {
+ if (numberOfReRenders > 0) {
+ throw new Error('Rendered more hooks than during the previous render');
+ }
+
+ return {
+ memoizedState: null,
+ queue: null,
+ next: null
+ };
+}
+
+function createWorkInProgressHook() {
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ if (firstWorkInProgressHook === null) {
+ isReRender = false;
+ firstWorkInProgressHook = workInProgressHook = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = firstWorkInProgressHook;
+ }
+ } else {
+ if (workInProgressHook.next === null) {
+ isReRender = false; // Append to the end of the list
+
+ workInProgressHook = workInProgressHook.next = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = workInProgressHook.next;
+ }
+ }
+
+ return workInProgressHook;
+}
+
+function prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState) {
+ currentlyRenderingComponent = componentIdentity;
+ currentlyRenderingTask = task;
+ currentlyRenderingRequest = request;
+ currentlyRenderingKeyPath = keyPath;
+ // didScheduleRenderPhaseUpdate = false;
+ // firstWorkInProgressHook = null;
+ // numberOfReRenders = 0;
+ // renderPhaseUpdates = null;
+ // workInProgressHook = null;
+
+
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ thenableState = prevThenableState;
+}
+function finishHooks(Component, props, children, refOrContext) {
+ // This must be called after every function component to prevent hooks from
+ // being used in classes.
+ while (didScheduleRenderPhaseUpdate) {
+ // Updates were scheduled during the render phase. They are stored in
+ // the `renderPhaseUpdates` map. Call the component again, reusing the
+ // work-in-progress hooks and applying the additional updates on top. Keep
+ // restarting until no more updates are scheduled.
+ didScheduleRenderPhaseUpdate = false;
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ numberOfReRenders += 1; // Start over from the beginning of the list
+
+ workInProgressHook = null;
+ children = Component(props, refOrContext);
+ }
+
+ resetHooksState();
+ return children;
+}
+function getThenableStateAfterSuspending() {
+ const state = thenableState;
+ thenableState = null;
+ return state;
+}
+function checkDidRenderIdHook() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ const didRenderIdHook = localIdCounter !== 0;
+ return didRenderIdHook;
+}
+function getFormStateCount() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateCounter;
+}
+function getFormStateMatchingIndex() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateMatchingIndex;
+} // Reset the internal hooks state if an error occurs while rendering a component
+
+function resetHooksState() {
+
+ currentlyRenderingComponent = null;
+ currentlyRenderingTask = null;
+ currentlyRenderingRequest = null;
+ currentlyRenderingKeyPath = null;
+ didScheduleRenderPhaseUpdate = false;
+ firstWorkInProgressHook = null;
+ numberOfReRenders = 0;
+ renderPhaseUpdates = null;
+ workInProgressHook = null;
+}
+
+function readContext(context) {
+
+ return readContext$1(context);
+}
+
+function useContext(context) {
+
+ resolveCurrentlyRenderingComponent();
+ return readContext$1(context);
+}
+
+function basicStateReducer(state, action) {
+ // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
+ return typeof action === 'function' ? action(state) : action;
+}
+
+function useState(initialState) {
+
+ return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers
+ initialState);
+}
+function useReducer(reducer, initialArg, init) {
+
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+
+ if (isReRender) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ // current hook.
+ const queue = workInProgressHook.queue;
+ const dispatch = queue.dispatch;
+
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate !== undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.delete(queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ let newState = workInProgressHook.memoizedState;
+ let update = firstRenderPhaseUpdate;
+
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ const action = update.action;
+
+ newState = reducer(newState, action);
+
+
+ update = update.next;
+ } while (update !== null); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ workInProgressHook.memoizedState = newState;
+ return [newState, dispatch];
+ }
+ } // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ return [workInProgressHook.memoizedState, dispatch];
+ } else {
+
+ let initialState;
+
+ if (reducer === basicStateReducer) {
+ // Special case for `useState`.
+ initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
+ } else {
+ initialState = init !== undefined ? init(initialArg) : initialArg;
+ }
+
+
+ workInProgressHook.memoizedState = initialState; // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ const queue = workInProgressHook.queue = {
+ last: null,
+ dispatch: null
+ };
+ const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ return [workInProgressHook.memoizedState, dispatch];
+ }
+}
+
+function useMemo(nextCreate, deps) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const nextDeps = deps === undefined ? null : deps;
+
+ if (workInProgressHook !== null) {
+ const prevState = workInProgressHook.memoizedState;
+
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ const prevDeps = prevState[1];
+
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ }
+
+ const nextValue = nextCreate();
+
+
+ workInProgressHook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function useRef(initialValue) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const previousRef = workInProgressHook.memoizedState;
+
+ if (previousRef === null) {
+ const ref = {
+ current: initialValue
+ };
+
+
+ workInProgressHook.memoizedState = ref;
+ return ref;
+ } else {
+ return previousRef;
+ }
+}
+
+function dispatchAction(componentIdentity, queue, action) {
+ if (numberOfReRenders >= RE_RENDER_LIMIT) {
+ throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.');
+ }
+
+ if (componentIdentity === currentlyRenderingComponent) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ const update = {
+ action,
+ next: null
+ };
+
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate === undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+
+ lastRenderPhaseUpdate.next = update;
+ }
+ }
+}
+
+function useCallback(callback, deps) {
+ return useMemo(() => callback, deps);
+}
+
+function throwOnUseEffectEventCall() {
+ throw new Error("A function wrapped in useEffectEvent can't be called during rendering.");
+}
+
+function useEffectEvent(callback) {
+ // $FlowIgnore[incompatible-return]
+ return throwOnUseEffectEventCall;
+}
+
+function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
+ if (getServerSnapshot === undefined) {
+ throw new Error('Missing getServerSnapshot, which is required for ' + 'server-rendered content. Will revert to client rendering.');
+ }
+
+ return getServerSnapshot();
+}
+
+function useDeferredValue(value, initialValue) {
+ resolveCurrentlyRenderingComponent();
+
+ {
+ return initialValue !== undefined ? initialValue : value;
+ }
+}
+
+function unsupportedStartTransition() {
+ throw new Error('startTransition cannot be called during server rendering.');
+}
+
+function useTransition() {
+ resolveCurrentlyRenderingComponent();
+ return [false, unsupportedStartTransition];
+}
+
+function useHostTransitionStatus() {
+ resolveCurrentlyRenderingComponent();
+ return NotPendingTransition;
+}
+
+function unsupportedSetOptimisticState() {
+ throw new Error('Cannot update optimistic state while rendering.');
+}
+
+function useOptimistic(passthrough, reducer) {
+ resolveCurrentlyRenderingComponent();
+ return [passthrough, unsupportedSetOptimisticState];
+}
+
+function createPostbackFormStateKey(permalink, componentKeyPath, hookIndex) {
+ if (permalink !== undefined) {
+ // Don't bother to hash a permalink-based key since it's already short.
+ return 'p' + permalink;
+ } else {
+ // Append a node to the key path that represents the form state hook.
+ const keyPath = [componentKeyPath, null, hookIndex]; // Key paths are hashed to reduce the size. It does not need to be secure,
+ // and it's more important that it's fast than that it's completely
+ // collision-free.
+
+ const keyPathHash = createFastHashJS(JSON.stringify(keyPath));
+ return 'k' + keyPathHash;
+ }
+}
+
+function useFormState(action, initialState, permalink) {
+ resolveCurrentlyRenderingComponent(); // Count the number of useFormState hooks per component. We also use this to
+ // track the position of this useFormState hook relative to the other ones in
+ // this component, so we can generate a unique key for each one.
+
+ const formStateHookIndex = formStateCounter++;
+ const request = currentlyRenderingRequest; // $FlowIgnore[prop-missing]
+
+ const formAction = action.$$FORM_ACTION;
+
+ if (typeof formAction === 'function') {
+ // This is a server action. These have additional features to enable
+ // MPA-style form submissions with progressive enhancement.
+ // TODO: If the same permalink is passed to multiple useFormStates, and
+ // they all have the same action signature, Fizz will pass the postback
+ // state to all of them. We should probably only pass it to the first one,
+ // and/or warn.
+ // The key is lazily generated and deduped so the that the keypath doesn't
+ // get JSON.stringify-ed unnecessarily, and at most once.
+ let nextPostbackStateKey = null; // Determine the current form state. If we received state during an MPA form
+ // submission, then we will reuse that, if the action identity matches.
+ // Otherwise we'll use the initial state argument. We will emit a comment
+ // marker into the stream that indicates whether the state was reused.
+
+ let state = initialState;
+ const componentKeyPath = currentlyRenderingKeyPath;
+ const postbackFormState = getFormState(request); // $FlowIgnore[prop-missing]
+
+ const isSignatureEqual = action.$$IS_SIGNATURE_EQUAL;
+
+ if (postbackFormState !== null && typeof isSignatureEqual === 'function') {
+ const postbackKey = postbackFormState[1];
+ const postbackReferenceId = postbackFormState[2];
+ const postbackBoundArity = postbackFormState[3];
+
+ if (isSignatureEqual.call(action, postbackReferenceId, postbackBoundArity)) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+
+ if (postbackKey === nextPostbackStateKey) {
+ // This was a match
+ formStateMatchingIndex = formStateHookIndex; // Reuse the state that was submitted by the form.
+
+ state = postbackFormState[0];
+ }
+ }
+ } // Bind the state to the first argument of the action.
+
+
+ const boundAction = action.bind(null, state); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ }; // $FlowIgnore[prop-missing]
+
+
+ if (typeof boundAction.$$FORM_ACTION === 'function') {
+ // $FlowIgnore[prop-missing]
+ dispatch.$$FORM_ACTION = prefix => {
+ const metadata = boundAction.$$FORM_ACTION(prefix); // Override the action URL
+
+ if (permalink !== undefined) {
+
+ permalink += '';
+ metadata.action = permalink;
+ }
+
+ const formData = metadata.data;
+
+ if (formData) {
+ if (nextPostbackStateKey === null) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+ }
+
+ formData.append('$ACTION_KEY', nextPostbackStateKey);
+ }
+
+ return metadata;
+ };
+ }
+
+ return [state, dispatch];
+ } else {
+ // This is not a server action, so the implementation is much simpler.
+ // Bind the state to the first argument of the action.
+ const boundAction = action.bind(null, initialState); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ };
+
+ return [initialState, dispatch];
+ }
+}
+
+function useId() {
+ const task = currentlyRenderingTask;
+ const treeId = getTreeId(task.treeContext);
+ const resumableState = currentResumableState;
+
+ if (resumableState === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component.');
+ }
+
+ const localId = localIdCounter++;
+ return makeId(resumableState, treeId, localId);
+}
+
+function use(usable) {
+ if (usable !== null && typeof usable === 'object') {
+ // $FlowFixMe[method-unbinding]
+ if (typeof usable.then === 'function') {
+ // This is a thenable.
+ const thenable = usable;
+ return unwrapThenable(thenable);
+ } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = usable;
+ return readContext(context);
+ }
+ } // eslint-disable-next-line react-internal/safe-string-coercion
+
+
+ throw new Error('An unsupported type was passed to use(): ' + String(usable));
+}
+
+function unwrapThenable(thenable) {
+ const index = thenableIndexCounter;
+ thenableIndexCounter += 1;
+
+ if (thenableState === null) {
+ thenableState = createThenableState();
+ }
+
+ return trackUsedThenable(thenableState, thenable, index);
+}
+
+function unsupportedRefresh() {
+ throw new Error('Cache cannot be refreshed during server rendering.');
+}
+
+function useCacheRefresh() {
+ return unsupportedRefresh;
+}
+
+function useMemoCache(size) {
+ const data = new Array(size);
+
+ for (let i = 0; i < size; i++) {
+ data[i] = REACT_MEMO_CACHE_SENTINEL;
+ }
+
+ return data;
+}
+
+function noop$1() {}
+
+const HooksDispatcher = {
+ readContext,
+ use,
+ useContext,
+ useMemo,
+ useReducer,
+ useRef,
+ useState,
+ useInsertionEffect: noop$1,
+ useLayoutEffect: noop$1,
+ useCallback,
+ // useImperativeHandle is not run in the server environment
+ useImperativeHandle: noop$1,
+ // Effects are not run in the server environment.
+ useEffect: noop$1,
+ // Debugging effect
+ useDebugValue: noop$1,
+ useDeferredValue,
+ useTransition,
+ useId,
+ // Subscriptions are not setup in a server environment.
+ useSyncExternalStore
+};
+
+{
+ HooksDispatcher.useCacheRefresh = useCacheRefresh;
+}
+
+{
+ HooksDispatcher.useEffectEvent = useEffectEvent;
+}
+
+{
+ HooksDispatcher.useMemoCache = useMemoCache;
+}
+
+{
+ HooksDispatcher.useHostTransitionStatus = useHostTransitionStatus;
+}
+
+{
+ HooksDispatcher.useOptimistic = useOptimistic;
+ HooksDispatcher.useFormState = useFormState;
+}
+
+let currentResumableState = null;
+function setCurrentResumableState(resumableState) {
+ currentResumableState = resumableState;
+}
+
+function getCacheSignal() {
+ throw new Error('Not implemented.');
+}
+
+function getCacheForType(resourceType) {
+ throw new Error('Not implemented.');
+}
+
+const DefaultCacheDispatcher = {
+ getCacheSignal,
+ getCacheForType
+};
+
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
+const ReactCurrentCache = ReactSharedInternals.ReactCurrentCache;
+// The name might be minified but we assume that it's going to be the same generated name. Typically
+// because it's just the same compiled output in practice.
+// resume with segmentID at the index
+
+const CLIENT_RENDERED = 4; // if it errors or infinitely suspends
+
+const PENDING = 0;
+const COMPLETED = 1;
+const FLUSHED = 2;
+const ABORTED = 3;
+const ERRORED = 4;
+const POSTPONED = 5;
+const OPEN = 0;
+const CLOSING = 1;
+const CLOSED = 2; // This is a default heuristic for how to split up the HTML content into progressive
+// loading. Our goal is to be able to display additional new content about every 500ms.
+// Faster than that is unnecessary and should be throttled on the client. It also
+// adds unnecessary overhead to do more splits. We don't know if it's a higher or lower
+// end device but higher end suffer less from the overhead than lower end does from
+// not getting small enough pieces. We error on the side of low end.
+// We base this on low end 3G speeds which is about 500kbits per second. We assume
+// that there can be a reasonable drop off from max bandwidth which leaves you with
+// as little as 80%. We can receive half of that each 500ms - at best. In practice,
+// a little bandwidth is lost to processing and contention - e.g. CSS and images that
+// are downloaded along with the main content. So we estimate about half of that to be
+// the lower end throughput. In other words, we expect that you can at least show
+// about 12.5kb of content per 500ms. Not counting starting latency for the first
+// paint.
+// 500 * 1024 / 8 * .8 * 0.5 / 2
+
+const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
+
+function defaultErrorHandler(error) {
+ console['error'](error); // Don't transform to our wrapper
+
+ return null;
+}
+
+function noop() {}
+
+function createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, formState) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState,
+ renderState,
+ rootFormatContext,
+ progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: 0,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: formState === undefined ? null : formState
+ }; // This segment represents the root fallback.
+
+ const rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false); // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+function createPrerenderRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone) {
+ const request = createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, undefined); // Start tracking postponed holes during this render.
+
+ request.trackedPostpones = {
+ workingMap: new Map(),
+ rootNodes: [],
+ rootSlots: null
+ };
+ return request;
+}
+function resumeRequest(children, postponedState, renderState, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState: postponedState.resumableState,
+ renderState,
+ rootFormatContext: postponedState.rootFormatContext,
+ progressiveChunkSize: postponedState.progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: postponedState.nextSegmentId,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: null
+ };
+
+ if (typeof postponedState.replaySlots === 'number') {
+ const resumedId = postponedState.replaySlots; // We have a resume slot at the very root. This is effectively just a full rerender.
+
+ const rootSegment = createPendingSegment(request, 0, null, postponedState.rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false);
+ rootSegment.id = resumedId; // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, postponedState.rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+ }
+
+ const replay = {
+ nodes: postponedState.replayNodes,
+ slots: postponedState.replaySlots,
+ pendingTasks: 0
+ };
+ const rootTask = createReplayTask(request, null, replay, children, -1, null, abortSet, null, postponedState.rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+let currentRequest = null;
+function resolveRequest() {
+ if (currentRequest) return currentRequest;
+
+ if (supportsRequestStorage) {
+ const store = requestStorage.getStore();
+ if (store) return store;
+ }
+
+ return null;
+}
+
+function pingTask(request, task) {
+ const pingedTasks = request.pingedTasks;
+ pingedTasks.push(task);
+
+ if (request.pingedTasks.length === 1) {
+ request.flushScheduled = request.destination !== null;
+ scheduleWork(() => performWork(request));
+ }
+}
+
+function createSuspenseBoundary(request, fallbackAbortableTasks) {
+ return {
+ status: PENDING,
+ rootSegmentID: -1,
+ parentFlushed: false,
+ pendingTasks: 0,
+ completedSegments: [],
+ byteSize: 0,
+ fallbackAbortableTasks,
+ errorDigest: null,
+ resources: createBoundaryResources(),
+ trackedContentKeyPath: null,
+ trackedFallbackNode: null
+ };
+}
+
+function createRenderTask(request, thenableState, node, childIndex, blockedBoundary, blockedSegment, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ const task = {
+ replay: null,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createReplayTask(request, thenableState, replay, node, childIndex, blockedBoundary, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ replay.pendingTasks++;
+ const task = {
+ replay,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment: null,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createPendingSegment(request, index, boundary, parentFormatContext, lastPushedText, textEmbedded) {
+ return {
+ status: PENDING,
+ id: -1,
+ // lazily assigned later
+ index,
+ parentFlushed: false,
+ chunks: [],
+ children: [],
+ parentFormatContext,
+ boundary,
+ lastPushedText,
+ textEmbedded
+ };
+} // DEV-only global reference to the currently executing task
+
+function popComponentStackInDEV(task) {
+} // stash the component stack of an unwinding error until it is processed
+
+function logPostpone(request, reason) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ request.onPostpone(reason);
+}
+
+function logRecoverableError(request, error) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ const errorDigest = request.onError(error);
+
+ if (errorDigest != null && typeof errorDigest !== 'string') {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead");
+ }
+
+ return errorDigest;
+}
+
+function fatalError(request, error) {
+ // This is called outside error handling code such as if the root errors outside
+ // a suspense boundary or if the root suspense boundary's fallback errors.
+ // It's also called if React itself or its host configs errors.
+ const onShellError = request.onShellError;
+ onShellError(error);
+ const onFatalError = request.onFatalError;
+ onFatalError(error);
+
+ if (request.destination !== null) {
+ request.status = CLOSED;
+ closeWithError(request.destination, error);
+ } else {
+ request.status = CLOSING;
+ request.fatalError = error;
+ }
+}
+
+function renderSuspenseBoundary(request, someTask, keyPath, props) {
+ if (someTask.replay !== null) {
+ // If we're replaying through this pass, it means we're replaying through
+ // an already completed Suspense boundary. It's too late to do anything about it
+ // so we can just render through it.
+ const prevKeyPath = someTask.keyPath;
+ someTask.keyPath = keyPath;
+ const content = props.children;
+
+ try {
+ renderNode(request, someTask, content, -1);
+ } finally {
+ someTask.keyPath = prevKeyPath;
+ }
+
+ return;
+ } // $FlowFixMe: Refined.
+
+
+ const task = someTask;
+ const prevKeyPath = task.keyPath;
+ const parentBoundary = task.blockedBoundary;
+ const parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for
+ // the fallback so that we can later replace that segment with the content.
+ // This also lets us split out the main content even if it doesn't suspend,
+ // in case it ends up generating a large subtree of content.
+
+ const fallback = props.fallback;
+ const content = props.children;
+ const fallbackAbortSet = new Set();
+ const newBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+
+ if (request.trackedPostpones !== null) {
+ newBoundary.trackedContentKeyPath = keyPath;
+ }
+
+ const insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback.
+
+ const boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false);
+ parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent
+
+ parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately.
+
+ const contentRootSegment = createPendingSegment(request, 0, null, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is
+ // no parent segment so there's nothing to wait on.
+
+ contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks.
+ // I suspect that there might be some efficiency benefits from not creating the suspended task
+ // and instead just using the stack if possible.
+ // TODO: Call this directly instead of messing with saving and restoring contexts.
+ // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and which segment
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = newBoundary;
+ task.blockedSegment = contentRootSegment;
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, newBoundary.resources);
+ }
+
+ task.keyPath = keyPath;
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+ pushSegmentFinale(contentRootSegment.chunks, request.renderState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded);
+ contentRootSegment.status = COMPLETED;
+ queueCompletedSegment(newBoundary, contentRootSegment);
+
+ if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
+ newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ contentRootSegment.status = ERRORED;
+ newBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ newBoundary.errorDigest = errorDigest;
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.blockedSegment = parentSegment;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]];
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones !== null) {
+ // We create a detached replay node to track any postpones inside the fallback.
+ const fallbackReplayNode = [fallbackKeyPath[1], fallbackKeyPath[2], [], null];
+ trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
+
+ if (newBoundary.status === POSTPONED) {
+ // This must exist now.
+ const boundaryReplayNode = trackedPostpones.workingMap.get(keyPath);
+ boundaryReplayNode[4] = fallbackReplayNode;
+ } else {
+ // We might not inject it into the postponed tree, unless the content actually
+ // postpones too. We need to keep track of it until that happpens.
+ newBoundary.trackedFallbackNode = fallbackReplayNode;
+ }
+ } // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+
+ const suspendedFallbackTask = createRenderTask(request, null, fallback, -1, parentBoundary, boundarySegment, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function replaySuspenseBoundary(request, task, keyPath, props, id, childNodes, childSlots, fallbackNodes, fallbackSlots) {
+ const prevKeyPath = task.keyPath;
+ const previousReplaySet = task.replay;
+ const parentBoundary = task.blockedBoundary;
+ const content = props.children;
+ const fallback = props.fallback;
+ const fallbackAbortSet = new Set();
+ const resumedBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = id; // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and replay node
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = resumedBoundary;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, resumedBoundary.resources);
+ }
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+
+ if (resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING) {
+ resumedBoundary.status = COMPLETED;
+ request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ resumedBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ resumedBoundary.errorDigest = errorDigest;
+
+ task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted.
+
+ request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task.
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.replay = previousReplaySet;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+ const fallbackReplay = {
+ nodes: fallbackNodes,
+ slots: fallbackSlots,
+ pendingTasks: 0
+ };
+ const suspendedFallbackTask = createReplayTask(request, null, fallbackReplay, fallback, -1, parentBoundary, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function renderHostElement(request, task, keyPath, type, props) {
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ const children = props.children; // TODO: Make this a Config for replaying.
+
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ } else {
+ // Render
+ const children = pushStartInstance(segment.chunks, type, props, request.resumableState, request.renderState, task.formatContext, segment.lastPushedText);
+ segment.lastPushedText = false;
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ pushEndInstance(segment.chunks, type, props, request.resumableState, prevContext);
+ segment.lastPushedText = false;
+ }
+}
+
+function shouldConstruct(Component) {
+ return Component.prototype && Component.prototype.isReactComponent;
+}
+
+function renderWithHooks(request, task, keyPath, prevThenableState, Component, props, secondArg) {
+ const componentIdentity = {};
+ prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState);
+ const result = Component(props, secondArg);
+ return finishHooks(Component, props, result, secondArg);
+}
+
+function finishClassComponent(request, task, keyPath, instance, Component, props) {
+ const nextChildren = instance.render();
+
+ {
+ const childContextTypes = Component.childContextTypes;
+
+ if (childContextTypes !== null && childContextTypes !== undefined) {
+ const previousContext = task.legacyContext;
+ const mergedContext = processChildContext(instance, Component, previousContext, childContextTypes);
+ task.legacyContext = mergedContext;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.legacyContext = previousContext;
+ return;
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderClassComponent(request, task, keyPath, Component, props) {
+ const maskedContext = getMaskedContext(Component, task.legacyContext) ;
+ const instance = constructClassInstance(Component, props, maskedContext);
+ mountClassInstance(instance, Component, props, maskedContext);
+ finishClassComponent(request, task, keyPath, instance, Component);
+}
+// components for some reason.
+
+function renderIndeterminateComponent(request, task, keyPath, prevThenableState, Component, props) {
+ let legacyContext;
+
+ {
+ legacyContext = getMaskedContext(Component, task.legacyContext);
+ }
+
+ const value = renderWithHooks(request, task, keyPath, prevThenableState, Component, props, legacyContext);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+
+ if ( // Run these checks in production only if the flag is off.
+ // Eventually we'll delete this branch altogether.
+ typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
+
+ mountClassInstance(value, Component, props, legacyContext);
+ finishClassComponent(request, task, keyPath, value, Component);
+ } else {
+
+ finishFunctionComponent(request, task, keyPath, value, hasId, formStateCount, formStateMatchingIndex);
+ }
+}
+
+function finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex) {
+ let didEmitFormStateMarkers = false;
+
+ if (formStateCount !== 0 && request.formState !== null) {
+ // For each useFormState hook, emit a marker that indicates whether we
+ // rendered using the form state passed at the root. We only emit these
+ // markers if form state is passed at the root.
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ didEmitFormStateMarkers = true;
+ const target = segment.chunks;
+
+ for (let i = 0; i < formStateCount; i++) {
+ if (i === formStateMatchingIndex) {
+ pushFormStateMarkerIsMatching(target);
+ } else {
+ pushFormStateMarkerIsNotMatching(target);
+ }
+ }
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+
+ if (hasId) {
+ // This component materialized an id. We treat this as its own level, with
+ // a single "child" slot.
+ const prevTreeContext = task.treeContext;
+ const totalChildren = 1;
+ const index = 0; // Modify the id context. Because we'll need to reset this if something
+ // suspends or errors, we'll use the non-destructive render path.
+
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
+ renderNode(request, task, children, -1); // Like the other contexts, this does not need to be in a finally block
+ // because renderNode takes care of unwinding the stack.
+
+ task.treeContext = prevTreeContext;
+ } else if (didEmitFormStateMarkers) {
+ // If there were formState hooks, we must use the non-destructive path
+ // because this component is not a pure indirection; we emitted markers
+ // to the stream.
+ renderNode(request, task, children, -1);
+ } else {
+ // We're now successfully past this task, and we haven't modified the
+ // context stack. We don't have to pop back to the previous task every
+ // again, so we can use the destructive recursive form.
+ renderNodeDestructive(request, task, null, children, -1);
+ }
+
+ task.keyPath = prevKeyPath;
+}
+
+function resolveDefaultProps(Component, baseProps) {
+ if (Component && Component.defaultProps) {
+ // Resolve default props. Taken from ReactElement
+ const props = assign({}, baseProps);
+ const defaultProps = Component.defaultProps;
+
+ for (const propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+
+ return props;
+ }
+
+ return baseProps;
+}
+
+function renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref) {
+ const children = renderWithHooks(request, task, keyPath, prevThenableState, type.render, props, ref);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+ finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex);
+}
+
+function renderMemo(request, task, keyPath, prevThenableState, type, props, ref) {
+ const innerType = type.type;
+ const resolvedProps = resolveDefaultProps(innerType, props);
+ renderElement(request, task, keyPath, prevThenableState, innerType, resolvedProps, ref);
+}
+
+function renderContextConsumer(request, task, keyPath, context, props) {
+
+ const render = props.children;
+
+ const newValue = readContext$1(context);
+ const newChildren = render(newValue);
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, newChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderContextProvider(request, task, keyPath, type, props) {
+ const context = type._context;
+ const value = props.value;
+ const children = props.children;
+
+ const prevKeyPath = task.keyPath;
+ task.context = pushProvider(context, value);
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, children, -1);
+ task.context = popProvider();
+ task.keyPath = prevKeyPath;
+}
+
+function renderLazyComponent(request, task, keyPath, prevThenableState, lazyComponent, props, ref) {
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+ const Component = init(payload);
+ const resolvedProps = resolveDefaultProps(Component, props);
+ renderElement(request, task, keyPath, prevThenableState, Component, resolvedProps, ref);
+}
+
+function renderOffscreen(request, task, keyPath, props) {
+ const mode = props.mode;
+
+ if (mode === 'hidden') ; else {
+ // A visible Offscreen boundary is treated exactly like a fragment: a
+ // pure indirection.
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ }
+}
+
+function renderElement(request, task, keyPath, prevThenableState, type, props, ref) {
+ if (typeof type === 'function') {
+ if (shouldConstruct(type)) {
+ renderClassComponent(request, task, keyPath, type, props);
+ return;
+ } else {
+ renderIndeterminateComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+
+ if (typeof type === 'string') {
+ renderHostElement(request, task, keyPath, type, props);
+ return;
+ }
+
+ switch (type) {
+ // LegacyHidden acts the same as a fragment. This only works because we
+ // currently assume that every instance of LegacyHidden is accompanied by a
+ // host component wrapper. In the hidden mode, the host component is given a
+ // `hidden` attribute, which ensures that the initial HTML is not visible.
+ // To support the use of LegacyHidden as a true fragment, without an extra
+ // DOM node, we would have to hide the initial HTML in some other way.
+ // TODO: Delete in LegacyHidden. It's an unstable API only used in the
+ // www build. As a migration step, we could add a special prop to Offscreen
+ // that simulates the old behavior (no hiding, no change to effects).
+ case REACT_LEGACY_HIDDEN_TYPE:
+ case REACT_DEBUG_TRACING_MODE_TYPE:
+ case REACT_STRICT_MODE_TYPE:
+ case REACT_PROFILER_TYPE:
+ case REACT_FRAGMENT_TYPE:
+ {
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_OFFSCREEN_TYPE:
+ {
+ renderOffscreen(request, task, keyPath, props);
+ return;
+ }
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ {
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_SCOPE_TYPE:
+ {
+
+ throw new Error('ReactDOMServer does not yet support scope components.');
+ }
+
+ case REACT_SUSPENSE_TYPE:
+ {
+ {
+ renderSuspenseBoundary(request, task, keyPath, props);
+ }
+
+ return;
+ }
+ }
+
+ if (typeof type === 'object' && type !== null) {
+ switch (type.$$typeof) {
+ case REACT_FORWARD_REF_TYPE:
+ {
+ renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_MEMO_TYPE:
+ {
+ renderMemo(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_PROVIDER_TYPE:
+ {
+ renderContextProvider(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_CONTEXT_TYPE:
+ {
+ renderContextConsumer(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_LAZY_TYPE:
+ {
+ renderLazyComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+ }
+
+ let info = '';
+
+ throw new Error('Element type is invalid: expected a string (for built-in ' + 'components) or a class/function (for composite components) ' + ("but got: " + (type == null ? type : typeof type) + "." + info));
+}
+
+function resumeNode(request, task, segmentId, node, childIndex) {
+ const prevReplay = task.replay;
+ const blockedBoundary = task.blockedBoundary;
+ const resumedSegment = createPendingSegment(request, 0, null, task.formatContext, false, false);
+ resumedSegment.id = segmentId;
+ resumedSegment.parentFlushed = true;
+
+ try {
+ // Convert the current ReplayTask to a RenderTask.
+ const renderTask = task;
+ renderTask.replay = null;
+ renderTask.blockedSegment = resumedSegment;
+ renderNode(request, task, node, childIndex);
+ resumedSegment.status = COMPLETED;
+
+ if (blockedBoundary === null) {
+ request.completedRootSegment = resumedSegment;
+ } else {
+ queueCompletedSegment(blockedBoundary, resumedSegment);
+
+ if (blockedBoundary.parentFlushed) {
+ request.partialBoundaries.push(blockedBoundary);
+ }
+ }
+ } finally {
+ // Restore to a ReplayTask.
+ task.replay = prevReplay;
+ task.blockedSegment = null;
+ }
+}
+
+function replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, replay) {
+ // We're replaying. Find the path to follow.
+ const replayNodes = replay.nodes;
+
+ for (let i = 0; i < replayNodes.length; i++) {
+ // Flow doesn't support refinement on tuples so we do it manually here.
+ const node = replayNodes[i];
+
+ if (keyOrIndex !== node[1]) {
+ continue;
+ }
+
+ if (node.length === 4) {
+ // Matched a replayable path.
+ // Let's double check that the component name matches as a precaution.
+ if (name !== null && name !== node[0]) {
+ throw new Error('Expected the resume to render <' + node[0] + '> in this slot but instead it rendered <' + name + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ const currentNode = task.node;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0 // TODO check remaining slots
+ ) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ if (task.node === currentNode) {
+ // This same element suspended so we need to pop the replay we just added.
+ task.replay = replay;
+ }
+
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay;
+ } else {
+ // Let's double check that the component type matches.
+ if (type !== REACT_SUSPENSE_TYPE) {
+ const expectedType = 'Suspense';
+ throw new Error('Expected the resume to render <' + expectedType + '> in this slot but instead it rendered <' + (getComponentNameFromType(type) || 'Unknown') + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ } // Matched a replayable path.
+
+
+ replaySuspenseBoundary(request, task, keyPath, props, node[5], node[2], node[3], node[4] === null ? [] : node[4][2], node[4] === null ? null : node[4][3]);
+ } // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+
+ replayNodes.splice(i, 1);
+ return;
+ } // We didn't find any matching nodes. We assume that this element was already
+ // rendered in the prelude and skip it.
+
+} // $FlowFixMe[missing-local-annot]
+
+function renderNodeDestructive(request, task, // The thenable state reused from the previous attempt, if any. This is almost
+// always null, except when called by retryTask.
+prevThenableState, node, childIndex) {
+ {
+ return renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex);
+ }
+} // This function by it self renders a node and consumes the task by mutating it
+// to update the current execution state.
+
+
+function renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex) {
+ if (task.replay !== null && typeof task.replay.slots === 'number') {
+ // TODO: Figure out a cheaper place than this hot path to do this check.
+ const resumeSegmentID = task.replay.slots;
+ resumeNode(request, task, resumeSegmentID, node, childIndex);
+ return;
+ } // Stash the node we're working on. We'll pick up from this task in case
+ // something suspends.
+
+
+ task.node = node;
+ task.childIndex = childIndex; // Handle object types
+
+ if (typeof node === 'object' && node !== null) {
+ switch (node.$$typeof) {
+ case REACT_ELEMENT_TYPE:
+ {
+ const element = node;
+ const type = element.type;
+ const key = element.key;
+ const props = element.props;
+ const ref = element.ref;
+ const name = getComponentNameFromType(type);
+ const keyOrIndex = key == null ? childIndex === -1 ? 0 : childIndex : key;
+ const keyPath = [task.keyPath, name, keyOrIndex];
+
+ if (task.replay !== null) {
+ replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, task.replay); // No matches found for this node. We assume it's already emitted in the
+ // prelude and skip it during the replay.
+ } else {
+ // We're doing a plain render.
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+ }
+
+ return;
+ }
+
+ case REACT_PORTAL_TYPE:
+ throw new Error('Portals are not currently supported by the server renderer. ' + 'Render them conditionally so that they only appear on the client render.');
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyNode = node;
+ const payload = lazyNode._payload;
+ const init = lazyNode._init;
+ let resolvedNode;
+
+ {
+ resolvedNode = init(payload);
+ }
+
+ renderNodeDestructive(request, task, null, resolvedNode, childIndex);
+ return;
+ }
+ }
+
+ if (isArray(node)) {
+ renderChildrenArray(request, task, node, childIndex);
+ return;
+ }
+
+ const iteratorFn = getIteratorFn(node);
+
+ if (iteratorFn) {
+
+ const iterator = iteratorFn.call(node);
+
+ if (iterator) {
+ // We need to know how many total children are in this set, so that we
+ // can allocate enough id slots to acommodate them. So we must exhaust
+ // the iterator before we start recursively rendering the children.
+ // TODO: This is not great but I think it's inherent to the id
+ // generation algorithm.
+ let step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that.
+
+ if (!step.done) {
+ const children = [];
+
+ do {
+ children.push(step.value);
+ step = iterator.next();
+ } while (!step.done);
+
+ renderChildrenArray(request, task, children, childIndex);
+ return;
+ }
+
+ return;
+ }
+ } // Usables are a valid React node type. When React encounters a Usable in
+ // a child position, it unwraps it using the same algorithm as `use`. For
+ // example, for promises, React will throw an exception to unwind the
+ // stack, then replay the component once the promise resolves.
+ //
+ // A difference from `use` is that React will keep unwrapping the value
+ // until it reaches a non-Usable type.
+ //
+ // e.g. Usable>> should resolve to T
+
+
+ const maybeUsable = node;
+
+ if (typeof maybeUsable.then === 'function') {
+ const thenable = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable), childIndex);
+ }
+
+ if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, readContext$1(context), childIndex);
+ } // $FlowFixMe[method-unbinding]
+
+
+ const childString = Object.prototype.toString.call(node);
+ throw new Error("Objects are not valid as a React child (found: " + (childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString) + "). " + 'If you meant to render a collection of children, use an array ' + 'instead.');
+ }
+
+ if (typeof node === 'string') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+
+ if (typeof node === 'number') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, '' + node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+}
+
+function replayFragment(request, task, children, childIndex) {
+ // If we're supposed follow this array, we'd expect to see a ReplayNode matching
+ // this fragment.
+ const replay = task.replay;
+ const replayNodes = replay.nodes;
+
+ for (let j = 0; j < replayNodes.length; j++) {
+ const node = replayNodes[j];
+
+ if (node[1] !== childIndex) {
+ continue;
+ } // Matched a replayable path.
+
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderChildrenArray(request, task, children, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+ // This is an error, stash the component stack if it is null.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay; // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ replayNodes.splice(j, 1);
+ break;
+ }
+}
+
+function renderChildrenArray(request, task, children, childIndex) {
+ const prevKeyPath = task.keyPath;
+
+ if (childIndex !== -1) {
+ task.keyPath = [task.keyPath, 'Fragment', childIndex];
+
+ if (task.replay !== null) {
+ replayFragment(request, // $FlowFixMe: Refined.
+ task, children, childIndex);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ const prevTreeContext = task.treeContext;
+ const totalChildren = children.length;
+
+ if (task.replay !== null) {
+ // Replay
+ // First we need to check if we have any resume slots at this level.
+ const resumeSlots = task.replay.slots;
+
+ if (resumeSlots !== null && typeof resumeSlots === 'object') {
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ const resumeSegmentID = resumeSlots[i]; // TODO: If this errors we should still continue with the next sibling.
+
+ if (typeof resumeSegmentID === 'number') {
+ resumeNode(request, task, resumeSegmentID, node, i); // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ delete resumeSlots[i];
+ } else {
+ renderNode(request, task, node, i);
+ }
+ }
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ renderNode(request, task, node, i);
+ } // Because this context is always set right before rendering every child, we
+ // only need to reset it to the previous value at the very end.
+
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+}
+
+function trackPostpone(request, trackedPostpones, task, segment) {
+ segment.status = POSTPONED;
+ const keyPath = task.keyPath;
+ const boundary = task.blockedBoundary;
+
+ if (boundary === null) {
+ segment.id = request.nextSegmentId++;
+ trackedPostpones.rootSlots = segment.id;
+
+ if (request.completedRootSegment !== null) {
+ // Postpone the root if this was a deeper segment.
+ request.completedRootSegment.status = POSTPONED;
+ }
+
+ return;
+ }
+
+ if (boundary !== null && boundary.status === PENDING) {
+ boundary.status = POSTPONED; // We need to eagerly assign it an ID because we'll need to refer to
+ // it before flushing and we know that we can't inline it.
+
+ boundary.rootSegmentID = request.nextSegmentId++;
+ const boundaryKeyPath = boundary.trackedContentKeyPath;
+
+ if (boundaryKeyPath === null) {
+ throw new Error('It should not be possible to postpone at the root. This is a bug in React.');
+ }
+
+ const fallbackReplayNode = boundary.trackedFallbackNode;
+ const children = [];
+
+ if (boundaryKeyPath === keyPath && task.childIndex === -1) {
+ // Since we postponed directly in the Suspense boundary we can't have written anything
+ // to its segment. Therefore this will end up becoming the root segment.
+ segment.id = boundary.rootSegmentID; // We postponed directly inside the Suspense boundary so we mark this for resuming.
+
+ const boundaryNode = [boundaryKeyPath[1], boundaryKeyPath[2], children, boundary.rootSegmentID, fallbackReplayNode, boundary.rootSegmentID];
+ trackedPostpones.workingMap.set(boundaryKeyPath, boundaryNode);
+ addToReplayParent(boundaryNode, boundaryKeyPath[0], trackedPostpones);
+ return;
+ } else {
+ let boundaryNode = trackedPostpones.workingMap.get(boundaryKeyPath);
+
+ if (boundaryNode === undefined) {
+ boundaryNode = [boundaryKeyPath[1], boundaryKeyPath[2], children, null, fallbackReplayNode, boundary.rootSegmentID];
+ trackedPostpones.workingMap.set(boundaryKeyPath, boundaryNode);
+ addToReplayParent(boundaryNode, boundaryKeyPath[0], trackedPostpones);
+ } else {
+ // Upgrade to ReplaySuspenseBoundary.
+ const suspenseBoundary = boundaryNode;
+ suspenseBoundary[4] = fallbackReplayNode;
+ suspenseBoundary[5] = boundary.rootSegmentID;
+ } // Fall through to add the child node.
+
+ }
+ } // We know that this will leave a hole so we might as well assign an ID now.
+ // We might have one already if we had a parent that gave us its ID.
+
+
+ if (segment.id === -1) {
+ if (segment.parentFlushed && boundary !== null) {
+ // If this segment's parent was already flushed, it means we really just
+ // skipped the parent and this segment is now the root.
+ segment.id = boundary.rootSegmentID;
+ } else {
+ segment.id = request.nextSegmentId++;
+ }
+ }
+
+ if (task.childIndex === -1) {
+ // Resume starting from directly inside the previous parent element.
+ if (keyPath === null) {
+ trackedPostpones.rootSlots = segment.id;
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let resumableNode = workingMap.get(keyPath);
+
+ if (resumableNode === undefined) {
+ resumableNode = [keyPath[1], keyPath[2], [], segment.id];
+ addToReplayParent(resumableNode, keyPath[0], trackedPostpones);
+ } else {
+ resumableNode[3] = segment.id;
+ }
+ }
+ } else {
+ let slots;
+
+ if (keyPath === null) {
+ slots = trackedPostpones.rootSlots;
+
+ if (slots === null) {
+ slots = trackedPostpones.rootSlots = {};
+ } else if (typeof slots === 'number') {
+ throw new Error('It should not be possible to postpone both at the root of an element ' + 'as well as a slot below. This is a bug in React.');
+ }
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let resumableNode = workingMap.get(keyPath);
+
+ if (resumableNode === undefined) {
+ slots = {};
+ resumableNode = [keyPath[1], keyPath[2], [], slots];
+ workingMap.set(keyPath, resumableNode);
+ addToReplayParent(resumableNode, keyPath[0], trackedPostpones);
+ } else {
+ slots = resumableNode[3];
+
+ if (slots === null) {
+ slots = resumableNode[3] = {};
+ } else if (typeof slots === 'number') {
+ throw new Error('It should not be possible to postpone both at the root of an element ' + 'as well as a slot below. This is a bug in React.');
+ }
+ }
+ }
+
+ slots[task.childIndex] = segment.id;
+ }
+}
+
+function injectPostponedHole(request, task, reason) {
+ logPostpone(request, reason); // Something suspended, we'll need to create a new segment and resolve it later.
+
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ return newSegment;
+}
+
+function spawnNewSuspendedReplayTask(request, task, thenableState, x) {
+ const newTask = createReplayTask(request, thenableState, task.replay, task.node, task.childIndex, task.blockedBoundary, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+}
+
+function spawnNewSuspendedRenderTask(request, task, thenableState, x) {
+ // Something suspended, we'll need to create a new segment and resolve it later.
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ const newTask = createRenderTask(request, thenableState, task.node, task.childIndex, task.blockedBoundary, newSegment, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+} // This is a non-destructive form of rendering a node. If it suspends it spawns
+// a new task and restores the context of this task to what it was before.
+
+
+function renderNode(request, task, node, childIndex) {
+ // Snapshot the current context in case something throws to interrupt the
+ // process.
+ const previousFormatContext = task.formatContext;
+ const previousLegacyContext = task.legacyContext;
+ const previousContext = task.context;
+ const previousKeyPath = task.keyPath;
+ const previousTreeContext = task.treeContext;
+
+ let x; // Store how much we've pushed at this point so we can reset it in case something
+ // suspended partially through writing something.
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState();
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedReplayTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode.
+
+ }
+ } else {
+ // Render
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedRenderTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+
+ if (request.trackedPostpones !== null && x.$$typeof === REACT_POSTPONE_TYPE && task.blockedBoundary !== null // bubble if we're postponing in the shell
+ ) {
+ // If we're tracking postpones, we inject a hole here and continue rendering
+ // sibling. Similar to suspending. If we're not tracking, we treat it more like
+ // an error. Notably this doesn't spawn a new task since nothing will fill it
+ // in during this prerender.
+ const postponeInstance = x;
+ const trackedPostpones = request.trackedPostpones;
+ const postponedSegment = injectPostponedHole(request, task, // We don't use ReplayTasks in prerenders.
+ postponeInstance.message);
+ trackPostpone(request, trackedPostpones, task, postponedSegment); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ return;
+ }
+ }
+ }
+ } // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ // Let's terminate the rest of the tree and don't render any siblings.
+
+
+ throw x;
+}
+
+function erroredReplay(request, boundary, error, replayNodes, resumeSlots) {
+ // Erroring during a replay doesn't actually cause an error by itself because
+ // that component has already rendered. What causes the error is the resumable
+ // points that we did not yet finish which will be below the point of the reset.
+ // For example, if we're replaying a path to a Suspense boundary that is not done
+ // that doesn't error the parent Suspense boundary.
+ // This might be a bit strange that the error in a parent gets thrown at a child.
+ // We log it only once and reuse the digest.
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ abortRemainingReplayNodes(request, boundary, replayNodes, resumeSlots, error, errorDigest);
+}
+
+function erroredTask(request, boundary, error) {
+ // Report the error to a global handler.
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ if (boundary === null) {
+ fatalError(request, error);
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+ // so we can flush it, if the parent already flushed.
+
+
+ if (boundary.parentFlushed) {
+ // We don't have a preference where in the queue this goes since it's likely
+ // to error on the client anyway. However, intentionally client-rendered
+ // boundaries should be flushed earlier so that they can start on the client.
+ // We reuse the same queue for errors.
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function abortTaskSoft(task) {
+ // This aborts task without aborting the parent boundary that it blocks.
+ // It's used for when we didn't need this task to complete the tree.
+ // If task was needed, then it should use abortTask instead.
+ const request = this;
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ finishedTask(request, boundary, segment);
+ }
+}
+
+function abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest) {
+ const resumedBoundary = createSuspenseBoundary(request, new Set());
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = rootSegmentID;
+ resumedBoundary.status = CLIENT_RENDERED;
+ resumedBoundary.errorDigest = errorDigest;
+
+ if (resumedBoundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(resumedBoundary);
+ }
+}
+
+function abortRemainingReplayNodes(request, boundary, nodes, slots, error, errorDigest) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+
+ if (node.length === 4) {
+ abortRemainingReplayNodes(request, boundary, node[2], node[3], error, errorDigest);
+ } else {
+ const boundaryNode = node;
+ const rootSegmentID = boundaryNode[5];
+ abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest);
+ }
+ } // Empty the set, since we've cleared it now.
+
+
+ nodes.length = 0;
+
+ if (slots !== null) {
+ // We had something still to resume in the parent boundary. We must trigger
+ // the error on the parent boundary since it's not able to complete.
+ if (boundary === null) {
+ throw new Error('We should not have any resumable nodes in the shell. ' + 'This is a bug in React.');
+ } else if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // Empty the set
+
+
+ if (typeof slots === 'object') {
+ for (const index in slots) {
+ delete slots[index];
+ }
+ }
+ }
+}
+
+function abortTask(task, request, error) {
+ // This aborts the task and aborts the parent that it blocks, putting it into
+ // client rendered mode.
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ }
+
+ if (boundary === null) {
+ if (request.status !== CLOSING && request.status !== CLOSED) {
+ const replay = task.replay;
+
+ if (replay === null) {
+ // We didn't complete the root so we have nothing to show. We can close
+ // the request;
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ return;
+ } else {
+ // If the shell aborts during a replay, that's not a fatal error. Instead
+ // we should be able to recover by client rendering all the root boundaries in
+ // the ReplaySet.
+ replay.pendingTasks--;
+
+ if (replay.pendingTasks === 0 && replay.nodes.length > 0) {
+ const errorDigest = logRecoverableError(request, error);
+ abortRemainingReplayNodes(request, null, replay.nodes, replay.slots, error, errorDigest);
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ }
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = logRecoverableError(request, error);
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // If this boundary was still pending then we haven't already cancelled its fallbacks.
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
+
+
+ boundary.fallbackAbortableTasks.forEach(fallbackTask => abortTask(fallbackTask, request, error));
+ boundary.fallbackAbortableTasks.clear();
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeShell(request) {
+ if (request.trackedPostpones === null) {
+ // We only emit early preloads on shell completion for renders. For prerenders
+ // we wait for the entire Request to finish because we are not responding to a
+ // live request and can wait for as much data as possible.
+ // we should only be calling completeShell when the shell is complete so we
+ // just use a literal here
+ const shellComplete = true;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ } // We have completed the shell so the shell can't error anymore.
+
+
+ request.onShellError = noop;
+ const onShellReady = request.onShellReady;
+ onShellReady();
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeAll(request) {
+ // During a render the shell must be complete if the entire request is finished
+ // however during a Prerender it is possible that the shell is incomplete because
+ // it postponed. We cannot use rootPendingTasks in the prerender case because
+ // those hit zero even when the shell postpones. Instead we look at the completedRootSegment
+ const shellComplete = request.trackedPostpones === null ? // Render, we assume it is completed
+ true : // Prerender Request, we use the state of the root segment
+ request.completedRootSegment === null || request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ const onAllReady = request.onAllReady;
+ onAllReady();
+}
+
+function queueCompletedSegment(boundary, segment) {
+ if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) {
+ // This is an empty segment. There's nothing to write, so we can instead transfer the ID
+ // to the child. That way any existing references point to the child.
+ const childSegment = segment.children[0];
+ childSegment.id = segment.id;
+ childSegment.parentFlushed = true;
+
+ if (childSegment.status === COMPLETED) {
+ queueCompletedSegment(boundary, childSegment);
+ }
+ } else {
+ const completedSegments = boundary.completedSegments;
+ completedSegments.push(segment);
+ }
+}
+
+function finishedTask(request, boundary, segment) {
+ if (boundary === null) {
+ if (segment !== null && segment.parentFlushed) {
+ if (request.completedRootSegment !== null) {
+ throw new Error('There can only be one root segment. This is a bug in React.');
+ }
+
+ request.completedRootSegment = segment;
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status === CLIENT_RENDERED) ; else if (boundary.pendingTasks === 0) {
+ if (boundary.status === PENDING) {
+ boundary.status = COMPLETED;
+ } // This must have been the last segment we were waiting on. This boundary is now complete.
+
+
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent segment already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ }
+ }
+
+ if (boundary.parentFlushed) {
+ // The segment might be part of a segment that didn't flush yet, but if the boundary's
+ // parent flushed, we need to schedule the boundary to be emitted.
+ request.completedBoundaries.push(boundary);
+ } // We can now cancel any pending task on the fallback since we won't need to show it anymore.
+ // This needs to happen after we read the parentFlushed flags because aborting can finish
+ // work which can trigger user code, which can start flushing, which can change those flags.
+ // If the boundary was POSTPONED, we still need to finish the fallback first.
+
+
+ if (boundary.status === COMPLETED) {
+ boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
+ boundary.fallbackAbortableTasks.clear();
+ }
+ } else {
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length === 1) {
+ // This is the first time since we last flushed that we completed anything.
+ // We can schedule this boundary to emit its partially completed segments early
+ // in case the parent has already been flushed.
+ if (boundary.parentFlushed) {
+ request.partialBoundaries.push(boundary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function retryTask(request, task) {
+ {
+ const blockedBoundary = task.blockedBoundary;
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, blockedBoundary ? blockedBoundary.resources : null);
+ }
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ retryReplayTask(request, // $FlowFixMe: Refined.
+ task);
+ } else {
+ retryRenderTask(request, // $FlowFixMe: Refined.
+ task, segment);
+ }
+}
+
+function retryRenderTask(request, task, segment) {
+ if (segment.status !== PENDING) {
+ // We completed this by other means before we had a chance to retry it.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+ pushSegmentFinale(segment.chunks, request.renderState, segment.lastPushedText, segment.textEmbedded);
+ task.abortSet.delete(task);
+ segment.status = COMPLETED;
+ finishedTask(request, task.blockedBoundary, segment);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ } else if (request.trackedPostpones !== null && x.$$typeof === REACT_POSTPONE_TYPE) {
+ // If we're tracking postpones, we mark this segment as postponed and finish
+ // the task without filling it in. If we're not tracking, we treat it more like
+ // an error.
+ const trackedPostpones = request.trackedPostpones;
+ task.abortSet.delete(task);
+ const postponeInstance = x;
+ logPostpone(request, postponeInstance.message);
+ trackPostpone(request, trackedPostpones, task, segment);
+ finishedTask(request, task.blockedBoundary, segment);
+ return;
+ }
+ }
+
+ task.abortSet.delete(task);
+ segment.status = ERRORED;
+ erroredTask(request, task.blockedBoundary, x);
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function retryReplayTask(request, task) {
+ if (task.replay.pendingTasks === 0) {
+ // There are no pending tasks working on this set, so we must have aborted.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ finishedTask(request, task.blockedBoundary, null);
+ } catch (thrownValue) {
+ resetHooksState();
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ erroredReplay(request, task.blockedBoundary, x, task.replay.nodes, task.replay.slots);
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function performWork(request) {
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ const prevContext = getActiveContext();
+ const prevDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = HooksDispatcher;
+ let prevCacheDispatcher;
+
+ {
+ prevCacheDispatcher = ReactCurrentCache.current;
+ ReactCurrentCache.current = DefaultCacheDispatcher;
+ }
+
+ const prevRequest = currentRequest;
+ currentRequest = request;
+
+ const prevResumableState = currentResumableState;
+ setCurrentResumableState(request.resumableState);
+
+ try {
+ const pingedTasks = request.pingedTasks;
+ let i;
+
+ for (i = 0; i < pingedTasks.length; i++) {
+ const task = pingedTasks[i];
+ retryTask(request, task);
+ }
+
+ pingedTasks.splice(0, i);
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ } finally {
+ setCurrentResumableState(prevResumableState);
+ ReactCurrentDispatcher.current = prevDispatcher;
+
+ {
+ ReactCurrentCache.current = prevCacheDispatcher;
+ }
+
+ if (prevDispatcher === HooksDispatcher) {
+ // This means that we were in a reentrant work loop. This could happen
+ // in a renderer that supports synchronous work like renderToString,
+ // when it's called from within another renderer.
+ // Normally we don't bother switching the contexts to their root/default
+ // values when leaving because we'll likely need the same or similar
+ // context again. However, when we're inside a synchronous loop like this
+ // we'll to restore the context to what it was before returning.
+ switchContext(prevContext);
+ }
+
+ currentRequest = prevRequest;
+ }
+}
+
+function flushSubtree(request, destination, segment) {
+ segment.parentFlushed = true;
+
+ switch (segment.status) {
+ case PENDING:
+ {
+ // We're emitting a placeholder for this segment to be filled in later.
+ // Therefore we'll need to assign it an ID - to refer to it by.
+ segment.id = request.nextSegmentId++; // Fallthrough
+ }
+
+ case POSTPONED:
+ {
+ const segmentID = segment.id; // When this segment finally completes it won't be embedded in text since it will flush separately
+
+ segment.lastPushedText = false;
+ segment.textEmbedded = false;
+ return writePlaceholder(destination, request.renderState, segmentID);
+ }
+
+ case COMPLETED:
+ {
+ segment.status = FLUSHED;
+ let r = true;
+ const chunks = segment.chunks;
+ let chunkIdx = 0;
+ const children = segment.children;
+
+ for (let childIdx = 0; childIdx < children.length; childIdx++) {
+ const nextChild = children[childIdx]; // Write all the chunks up until the next child.
+
+ for (; chunkIdx < nextChild.index; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ r = flushSegment(request, destination, nextChild);
+ } // Finally just write all the remaining chunks
+
+
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ if (chunkIdx < chunks.length) {
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
+ }
+
+ return r;
+ }
+
+ default:
+ {
+ throw new Error('Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.');
+ }
+ }
+}
+
+function flushSegment(request, destination, segment) {
+ const boundary = segment.boundary;
+
+ if (boundary === null) {
+ // Not a suspense boundary.
+ return flushSubtree(request, destination, segment);
+ }
+
+ boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to
+ // emit the content or the fallback now.
+
+ if (boundary.status === CLIENT_RENDERED) {
+ // Emit a client rendered suspense boundary wrapper.
+ // We never queue the inner boundary so we'll never emit its content or partial segments.
+ writeStartClientRenderedSuspenseBoundary(destination, request.renderState, boundary.errorDigest); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndClientRenderedSuspenseBoundary(destination);
+ } else if (boundary.status !== COMPLETED) {
+ if (boundary.status === PENDING) {
+ // For pending boundaries we lazily assign an ID to the boundary
+ // and root segment.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ }
+
+ if (boundary.completedSegments.length > 0) {
+ // If this is at least partially complete, we can queue it to be partially emitted early.
+ request.partialBoundaries.push(boundary);
+ } // This boundary is still loading. Emit a pending suspense boundary wrapper.
+
+
+ const id = boundary.rootSegmentID;
+ writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else if (boundary.byteSize > request.progressiveChunkSize) {
+ // This boundary is large and will be emitted separately so that we can progressively show
+ // other content. We add it to the queue during the flush because we have to ensure that
+ // the parent flushes first so that there's something to inject it into.
+ // We also have to make sure that it's emitted into the queue in a deterministic slot.
+ // I.e. we can't insert it here when it completes.
+ // Assign an ID to refer to the future content by.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper.
+
+ writeStartPendingSuspenseBoundary(destination, request.renderState, boundary.rootSegmentID); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else {
+ {
+ hoistResources(request.renderState, boundary.resources);
+ } // We can inline this boundary's content as a complete boundary.
+
+
+ writeStartCompletedSuspenseBoundary(destination);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length !== 1) {
+ throw new Error('A previously unvisited boundary must have exactly one root segment. This is a bug in React.');
+ }
+
+ const contentSegment = completedSegments[0];
+ flushSegment(request, destination, contentSegment);
+ return writeEndCompletedSuspenseBoundary(destination);
+ }
+}
+
+function flushClientRenderedBoundary(request, destination, boundary) {
+ return writeClientRenderBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack);
+}
+
+function flushSegmentContainer(request, destination, segment) {
+ writeStartSegment(destination, request.renderState, segment.parentFormatContext, segment.id);
+ flushSegment(request, destination, segment);
+ return writeEndSegment(destination, segment.parentFormatContext);
+}
+
+function flushCompletedBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+ flushPartiallyCompletedSegment(request, destination, boundary, segment);
+ }
+
+ completedSegments.length = 0;
+
+ {
+ writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+
+ return writeCompletedBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.resources);
+}
+
+function flushPartialBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+
+ if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) {
+ i++;
+ completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority
+ // might want to write later.
+
+ return false;
+ }
+ }
+
+ completedSegments.splice(0, i);
+
+ {
+ // The way this is structured we only write resources for partial boundaries
+ // if there is no backpressure. Later before we complete the boundary we
+ // will write resources regardless of backpressure before we emit the
+ // completion instruction
+ return writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+}
+
+function flushPartiallyCompletedSegment(request, destination, boundary, segment) {
+ if (segment.status === FLUSHED) {
+ // We've already flushed this inline.
+ return true;
+ }
+
+ const segmentID = segment.id;
+
+ if (segmentID === -1) {
+ // This segment wasn't previously referred to. This happens at the root of
+ // a boundary. We make kind of a leap here and assume this is the root.
+ const rootSegmentID = segment.id = boundary.rootSegmentID;
+
+ if (rootSegmentID === -1) {
+ throw new Error('A root segment ID must have been assigned by now. This is a bug in React.');
+ }
+
+ return flushSegmentContainer(request, destination, segment);
+ } else if (segmentID === boundary.rootSegmentID) {
+ // When we emit postponed boundaries, we might have assigned the ID already
+ // but it's still the root segment so we can't inject it into the parent yet.
+ return flushSegmentContainer(request, destination, segment);
+ } else {
+ flushSegmentContainer(request, destination, segment);
+ return writeCompletedSegmentInstruction(destination, request.resumableState, request.renderState, segmentID);
+ }
+}
+
+function flushCompletedQueues(request, destination) {
+ beginWriting();
+
+ try {
+ // The structure of this is to go through each queue one by one and write
+ // until the sink tells us to stop. When we should stop, we still finish writing
+ // that item fully and then yield. At that point we remove the already completed
+ // items up until the point we completed them.
+ let i;
+ const completedRootSegment = request.completedRootSegment;
+
+ if (completedRootSegment !== null) {
+ if (completedRootSegment.status === POSTPONED) {
+ // We postponed the root, so we write nothing.
+ return;
+ } else if (request.pendingRootTasks === 0) {
+ if (enableFloat) {
+ writePreamble(destination, request.resumableState, request.renderState, request.allPendingTasks === 0 && request.trackedPostpones === null);
+ }
+
+ flushSegment(request, destination, completedRootSegment);
+ request.completedRootSegment = null;
+ writeCompletedRoot(destination, request.renderState, request.resumableState);
+ } else {
+ // We haven't flushed the root yet so we don't need to check any other branches further down
+ return;
+ }
+ }
+
+ if (enableFloat) {
+ writeHoistables(destination, request.resumableState, request.renderState);
+ } // We emit client rendering instructions for already emitted boundaries first.
+ // This is so that we can signal to the client to start client rendering them as
+ // soon as possible.
+
+
+ const clientRenderedBoundaries = request.clientRenderedBoundaries;
+
+ for (i = 0; i < clientRenderedBoundaries.length; i++) {
+ const boundary = clientRenderedBoundaries[i];
+
+ if (!flushClientRenderedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ clientRenderedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries
+ // that are completely done since we can actually show them, than it is to emit
+ // any individual segments from a partially complete boundary.
+
+ const completedBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < completedBoundaries.length; i++) {
+ const boundary = completedBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ completedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before
+ // we continue with lower priorities.
+
+ completeWriting(destination);
+ beginWriting(destination); // TODO: Here we'll emit data used by hydration.
+ // Next we emit any segments of any boundaries that are partially complete
+ // but not deeply complete.
+
+ const partialBoundaries = request.partialBoundaries;
+
+ for (i = 0; i < partialBoundaries.length; i++) {
+ const boundary = partialBoundaries[i];
+
+ if (!flushPartialBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ partialBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had
+ // boundaries added to it in case they were too larged to be inlined.
+ // New ones might be added in this loop.
+
+ const largeBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < largeBoundaries.length; i++) {
+ const boundary = largeBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ largeBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ largeBoundaries.splice(0, i);
+ } finally {
+ if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because
+ // either they have pending task or they're complete.
+ ) {
+ request.flushScheduled = false;
+
+ {
+ // We write the trailing tags but only if don't have any data to resume.
+ // If we need to resume we'll write the postamble in the resume instead.
+ if (request.trackedPostpones === null) {
+ writePostamble(destination, request.resumableState);
+ }
+ }
+
+ completeWriting(destination);
+
+
+ close(destination); // We need to stop flowing now because we do not want any async contexts which might call
+ // float methods to initiate any flushes after this point
+
+ stopFlowing(request);
+ } else {
+ completeWriting(destination);
+ }
+ }
+}
+
+function startWork(request) {
+ request.flushScheduled = request.destination !== null;
+
+ if (supportsRequestStorage) {
+ scheduleWork(() => requestStorage.run(request, performWork, request));
+ } else {
+ scheduleWork(() => performWork(request));
+ }
+
+ if (request.trackedPostpones === null) {
+ // this is either a regular render or a resume. For regular render we want
+ // to call emitEarlyPreloads after the first performWork because we want
+ // are responding to a live request and need to balance sending something early
+ // (i.e. don't want for the shell to finish) but we need something to send.
+ // The only implementation of this is for DOM at the moment and during resumes nothing
+ // actually emits but the code paths here are the same.
+ // During a prerender we don't want to be too aggressive in emitting early preloads
+ // because we aren't responding to a live request and we can wait for the prerender to
+ // postpone before we emit anything.
+ if (supportsRequestStorage) {
+ scheduleWork(() => requestStorage.run(request, enqueueEarlyPreloadsAfterInitialWork, request));
+ } else {
+ scheduleWork(() => enqueueEarlyPreloadsAfterInitialWork(request));
+ }
+ }
+}
+
+function enqueueEarlyPreloadsAfterInitialWork(request) {
+ const shellComplete = request.pendingRootTasks === 0;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+
+function enqueueFlush(request) {
+ if (request.flushScheduled === false && // If there are pinged tasks we are going to flush anyway after work completes
+ request.pingedTasks.length === 0 && // If there is no destination there is nothing we can flush to. A flush will
+ // happen when we start flowing again
+ request.destination !== null) {
+ request.flushScheduled = true;
+ scheduleWork(() => {
+ // We need to existence check destination again here because it might go away
+ // in between the enqueueFlush call and the work execution
+ const destination = request.destination;
+
+ if (destination) {
+ flushCompletedQueues(request, destination);
+ } else {
+ request.flushScheduled = false;
+ }
+ });
+ }
+} // This function is intented to only be called during the pipe function for the Node builds.
+function startFlowing(request, destination) {
+ if (request.status === CLOSING) {
+ request.status = CLOSED;
+ closeWithError(destination, request.fatalError);
+ return;
+ }
+
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ if (request.destination !== null) {
+ // We're already flowing.
+ return;
+ }
+
+ request.destination = destination;
+
+ try {
+ flushCompletedQueues(request, destination);
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function stopFlowing(request) {
+ request.destination = null;
+} // This is called to early terminate a request. It puts all pending boundaries in client rendered state.
+
+function abort(request, reason) {
+ try {
+ const abortableTasks = request.abortableTasks;
+
+ if (abortableTasks.size > 0) {
+ const error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason;
+ abortableTasks.forEach(task => abortTask(task, request, error));
+ abortableTasks.clear();
+ }
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function flushResources(request) {
+ enqueueFlush(request);
+}
+function getFormState(request) {
+ return request.formState;
+}
+function getResumableState(request) {
+ return request.resumableState;
+}
+function getRenderState(request) {
+ return request.renderState;
+}
+
+function addToReplayParent(node, parentKeyPath, trackedPostpones) {
+ if (parentKeyPath === null) {
+ trackedPostpones.rootNodes.push(node);
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let parentNode = workingMap.get(parentKeyPath);
+
+ if (parentNode === undefined) {
+ parentNode = [parentKeyPath[1], parentKeyPath[2], [], null];
+ workingMap.set(parentKeyPath, parentNode);
+ addToReplayParent(parentNode, parentKeyPath[0], trackedPostpones);
+ }
+
+ parentNode[2].push(node);
+ }
+} // Returns the state of a postponed request or null if nothing was postponed.
+
+
+function getPostponedState(request) {
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones === null || trackedPostpones.rootNodes.length === 0 && trackedPostpones.rootSlots === null) {
+ // Reset. Let the flushing behave as if we completed the whole document.
+ request.trackedPostpones = null;
+ return null;
+ }
+
+ if (request.completedRootSegment !== null && request.completedRootSegment.status === POSTPONED) {
+ // We postponed the root so we didn't flush anything.
+ resetResumableState(request.resumableState, request.renderState);
+ }
+
+ return {
+ nextSegmentId: request.nextSegmentId,
+ rootFormatContext: request.rootFormatContext,
+ progressiveChunkSize: request.progressiveChunkSize,
+ resumableState: request.resumableState,
+ replayNodes: trackedPostpones.rootNodes,
+ replaySlots: trackedPostpones.rootSlots
+ };
+}
+
+function renderToReadableStream(children, options) {
+ return new Promise((resolve, reject) => {
+ let onFatalError;
+ let onAllReady;
+ const allReady = new Promise((res, rej) => {
+ onAllReady = res;
+ onFatalError = rej;
+ });
+
+ function onShellReady() {
+ const stream = new ReadableStream({
+ type: 'bytes',
+ pull: controller => {
+ startFlowing(request, controller);
+ },
+ cancel: reason => {
+ stopFlowing(request);
+ abort(request, reason);
+ }
+ }, // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
+ {
+ highWaterMark: 0
+ }); // TODO: Move to sub-classing ReadableStream.
+
+ stream.allReady = allReady;
+ resolve(stream);
+ }
+
+ function onShellError(error) {
+ // If the shell errors the caller of `renderToReadableStream` won't have access to `allReady`.
+ // However, `allReady` will be rejected by `onFatalError` as well.
+ // So we need to catch the duplicate, uncatchable fatal error in `allReady` to prevent a `UnhandledPromiseRejection`.
+ allReady.catch(() => {});
+ reject(error);
+ }
+
+ const onHeaders = options ? options.onHeaders : undefined;
+ let onHeadersImpl;
+
+ if (onHeaders) {
+ onHeadersImpl = headersDescriptor => {
+ onHeaders(new Headers(headersDescriptor));
+ };
+ }
+
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ const request = createRequest(children, resumableState, createRenderState(resumableState, options ? options.nonce : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, onHeadersImpl, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, onAllReady, onShellReady, onShellError, onFatalError, options ? options.onPostpone : undefined, options ? options.formState : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+function resume(children, postponedState, options) {
+ return new Promise((resolve, reject) => {
+ let onFatalError;
+ let onAllReady;
+ const allReady = new Promise((res, rej) => {
+ onAllReady = res;
+ onFatalError = rej;
+ });
+
+ function onShellReady() {
+ const stream = new ReadableStream({
+ type: 'bytes',
+ pull: controller => {
+ startFlowing(request, controller);
+ },
+ cancel: reason => {
+ stopFlowing(request);
+ abort(request, reason);
+ }
+ }, // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
+ {
+ highWaterMark: 0
+ }); // TODO: Move to sub-classing ReadableStream.
+
+ stream.allReady = allReady;
+ resolve(stream);
+ }
+
+ function onShellError(error) {
+ // If the shell errors the caller of `renderToReadableStream` won't have access to `allReady`.
+ // However, `allReady` will be rejected by `onFatalError` as well.
+ // So we need to catch the duplicate, uncatchable fatal error in `allReady` to prevent a `UnhandledPromiseRejection`.
+ allReady.catch(() => {});
+ reject(error);
+ }
+
+ const request = resumeRequest(children, postponedState, resumeRenderState(postponedState.resumableState, options ? options.nonce : undefined), options ? options.onError : undefined, onAllReady, onShellReady, onShellError, onFatalError, options ? options.onPostpone : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+function prerender(children, options) {
+ return new Promise((resolve, reject) => {
+ const onFatalError = reject;
+
+ function onAllReady() {
+ const stream = new ReadableStream({
+ type: 'bytes',
+ pull: controller => {
+ startFlowing(request, controller);
+ },
+ cancel: reason => {
+ stopFlowing(request);
+ abort(request, reason);
+ }
+ }, // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
+ {
+ highWaterMark: 0
+ });
+ const result = {
+ postponed: getPostponedState(request),
+ prelude: stream
+ };
+ resolve(result);
+ }
+
+ const onHeaders = options ? options.onHeaders : undefined;
+ let onHeadersImpl;
+
+ if (onHeaders) {
+ onHeadersImpl = headersDescriptor => {
+ onHeaders(new Headers(headersDescriptor));
+ };
+ }
+
+ const resources = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ const request = createPrerenderRequest(children, resources, createRenderState(resources, undefined, // nonce is not compatible with prerendered bootstrap scripts
+ options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, onHeadersImpl, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, onAllReady, undefined, undefined, onFatalError, options ? options.onPostpone : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+exports.prerender = prerender;
+exports.renderToReadableStream = renderToReadableStream;
+exports.resume = resume;
+exports.version = ReactVersion;
\ No newline at end of file
diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.min.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.min.js
index e37f59d388d48..f941804353d6b 100644
--- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.min.js
+++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.min.js
@@ -1,13 +1,11 @@
-/**
- * @license React
- * react-dom-server.edge.production.min.js
- *
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
/*
+ React
+ react-dom-server.edge.production.min.js
+
+ Copyright (c) Meta Platforms, Inc. and affiliates.
+
+ This source code is licensed under the MIT license found in the
+ LICENSE file in the root directory of this source tree.
JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
@@ -34,7 +32,7 @@
'use strict';var ba=require("next/dist/compiled/react-experimental"),ca=require("react-dom");
function da(a,b){var c=a.length&3;var d=a.length-c;var e=b;for(b=0;b>>16)&65535)<<16)&4294967295;f=f<<15|f>>>17;f=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295;e^=f;e=e<<13|e>>>19;e=5*(e&65535)+((5*(e>>>16)&65535)<<16)&4294967295;e=(e&65535)+27492+(((e>>>16)+58964&65535)<<16)}f=0;switch(c){case 3:f^=(a.charCodeAt(b+2)&255)<<
16;case 2:f^=(a.charCodeAt(b+1)&255)<<8;case 1:f^=a.charCodeAt(b)&255,f=3432918353*(f&65535)+((3432918353*(f>>>16)&65535)<<16)&4294967295,f=f<<15|f>>>17,e^=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295}e^=a.length;e^=e>>>16;e=2246822507*(e&65535)+((2246822507*(e>>>16)&65535)<<16)&4294967295;e^=e>>>13;e=3266489909*(e&65535)+((3266489909*(e>>>16)&65535)<<16)&4294967295;return(e^e>>>16)>>>0}var l=null,n=0;
-function r(a,b){if(0!==b.byteLength)if(512 '),bb=z("');
+const startScriptSrc = stringToPrecomputedChunk('');
+/**
+ * This escaping function is designed to work with bootstrapScriptContent and importMap only.
+ * because we know we are escaping the entire script. We can avoid for instance
+ * escaping html comment string sequences that are valid javascript as well because
+ * if there are no sebsequent '); // Since we store headers as strings we deal with their length in utf16 code units
+// rather than visual characters or the utf8 encoding that is used for most binary
+// serialization. Some common HTTP servers only allow for headers to be 4kB in length.
+// We choose a default length that is likely to be well under this already limited length however
+// pathological cases may still cause the utf-8 encoding of the headers to approach this limit.
+// It should also be noted that this maximum is a soft maximum. we have not reached the limit we will
+// allow one more header to be captured which means in practice if the limit is approached it will be exceeded
+
+const DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep track of what we've already written so we can refer back to it.
+// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
+// is set, the server will send instructions via data attributes (instead of inline scripts)
+
+function createRenderState(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+ const inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const completeSegmentData1 = stringToPrecomputedChunk('');
+const completeBoundaryData1 = stringToPrecomputedChunk('');
+const clientRenderData1 = stringToPrecomputedChunk('
+ return writeChunkAndReturn(destination, clientRenderDataEnd);
+ }
+}
+const regexForJSStringsInInstructionScripts = /[<\u2028\u2029]/g;
+
+function escapeJSStringsForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInInstructionScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const regexForJSStringsInScripts = /[&><\u2028\u2029]/g;
+
+function escapeJSObjectForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '&':
+ return '\\u0026';
+
+ case '>':
+ return '\\u003e';
+
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(''); // Tracks whether the boundary currently flushing is flushign style tags or has any
+// stylesheet dependencies not flushed in the Preamble.
+
+let currentlyRenderingBoundaryHasStylesToHoist = false; // Acts as a return value for the forEach execution of style tag flushing.
+
+let destinationHasCapacity = true;
+
+function flushStyleTagsLateForBoundary(styleQueue) {
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs;
+
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, lateStyleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ writeChunk(this, lateStyleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, lateStyleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ destinationHasCapacity = writeChunkAndReturn(this, lateStyleTagTemplateClose); // We wrote style tags for this boundary and we may need to emit a script
+ // to hoist them.
+
+ currentlyRenderingBoundaryHasStylesToHoist = true; // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function hasStylesToHoist(stylesheet) {
+ // We need to reveal boundaries with styles whenever a stylesheet it depends on is either
+ // not flushed or flushed after the preamble (shell).
+ if (stylesheet.state !== PREAMBLE) {
+ currentlyRenderingBoundaryHasStylesToHoist = true;
+ return true;
+ }
+
+ return false;
+}
+
+function writeResourcesForBoundary(destination, boundaryResources, renderState) {
+ // Reset these on each invocation, they are only safe to read in this function
+ currentlyRenderingBoundaryHasStylesToHoist = false;
+ destinationHasCapacity = true; // Flush style tags for each precedence this boundary depends on
+
+ boundaryResources.styles.forEach(flushStyleTagsLateForBoundary, destination); // Determine if this boundary has stylesheets that need to be awaited upon completion
+
+ boundaryResources.stylesheets.forEach(hasStylesToHoist);
+
+ if (currentlyRenderingBoundaryHasStylesToHoist) {
+ renderState.stylesToHoist = true;
+ }
+
+ return destinationHasCapacity;
+}
+
+function flushResource(resource) {
+ for (let i = 0; i < resource.length; i++) {
+ writeChunk(this, resource[i]);
+ }
+
+ resource.length = 0;
+}
+
+const stylesheetFlushingQueue = [];
+
+function flushStyleInPreamble(stylesheet, key, map) {
+ // We still need to encode stylesheet chunks
+ // because unlike most Hoistables and Resources we do not eagerly encode
+ // them during render. This is because if we flush late we have to send a
+ // different encoding and we don't want to encode multiple times
+ pushLinkImpl(stylesheetFlushingQueue, stylesheet.props);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ stylesheet.state = PREAMBLE;
+}
+
+const styleTagResourceOpen1 = stringToPrecomputedChunk('');
+
+function flushStylesInPreamble(styleQueue, precedence) {
+ const hasStylesheets = styleQueue.sheets.size > 0;
+ styleQueue.sheets.forEach(flushStyleInPreamble, this);
+ styleQueue.sheets.clear();
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs; // If we don't emit any stylesheets at this precedence we still need to maintain the precedence
+ // order so even if there are no rules for style tags at this precedence we emit an empty style
+ // tag with the data-precedence attribute
+
+ if (!hasStylesheets || hrefs.length) {
+ writeChunk(this, styleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, styleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ }
+
+ writeChunk(this, styleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ writeChunk(this, styleTagResourceClose); // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function preloadLateStyle(stylesheet) {
+ if (stylesheet.state === PENDING$1) {
+ stylesheet.state = PRELOADED;
+ const preloadProps = preloadAsStylePropsFromProps(stylesheet.props.href, stylesheet.props);
+ pushLinkImpl(stylesheetFlushingQueue, preloadProps);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ }
+}
+
+function preloadLateStyles(styleQueue) {
+ styleQueue.sheets.forEach(preloadLateStyle, this);
+ styleQueue.sheets.clear();
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+
+function writePreamble(destination, resumableState, renderState, willFlushAllSegments) {
+ // This function must be called exactly once on every request
+ if (!willFlushAllSegments && renderState.externalRuntimeScript) {
+ // If the root segment is incomplete due to suspended tasks
+ // (e.g. willFlushAllSegments = false) and we are using data
+ // streaming format, ensure the external runtime is sent.
+ // (User code could choose to send this even earlier by calling
+ // preinit(...), if they know they will suspend).
+ const _renderState$external = renderState.externalRuntimeScript,
+ src = _renderState$external.src,
+ chunks = _renderState$external.chunks;
+ internalPreinitScript(resumableState, renderState, src, chunks);
+ }
+
+ const htmlChunks = renderState.htmlChunks;
+ const headChunks = renderState.headChunks;
+ let i = 0; // Emit open tags before Hoistables and Resources
+
+ if (htmlChunks) {
+ // We have an to emit as part of the preamble
+ for (i = 0; i < htmlChunks.length; i++) {
+ writeChunk(destination, htmlChunks[i]);
+ }
+
+ if (headChunks) {
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } else {
+ // We did not render a head but we emitted an so we emit one now
+ writeChunk(destination, startChunkForTag('head'));
+ writeChunk(destination, endOfStartTag);
+ }
+ } else if (headChunks) {
+ // We do not have an but we do have a
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } // Emit high priority Hoistables
+
+
+ const charsetChunks = renderState.charsetChunks;
+
+ for (i = 0; i < charsetChunks.length; i++) {
+ writeChunk(destination, charsetChunks[i]);
+ }
+
+ charsetChunks.length = 0; // emit preconnect resources
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Flush unblocked stylesheets by precedence
+
+ renderState.styles.forEach(flushStylesInPreamble, destination);
+ const importMapChunks = renderState.importMapChunks;
+
+ for (i = 0; i < importMapChunks.length; i++) {
+ writeChunk(destination, importMapChunks[i]);
+ }
+
+ importMapChunks.length = 0;
+ renderState.bootstrapScripts.forEach(flushResource, destination);
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0; // Flush closing head if necessary
+
+ if (htmlChunks && headChunks === null) {
+ // We have an rendered but no rendered. We however inserted
+ // a up above so we need to emit the now. This is safe because
+ // if the main content contained the it would also have provided a
+ // . This means that all the content inside is either or
+ // invalid HTML
+ writeChunk(destination, endChunkForTag('head'));
+ }
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+function writeHoistables(destination, resumableState, renderState) {
+ let i = 0; // Emit high priority Hoistables
+ // We omit charsetChunks because we have already sent the shell and if it wasn't
+ // already sent it is too late now.
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Preload any stylesheets. these will emit in a render instruction that follows this
+ // but we want to kick off preloading as soon as possible
+
+ renderState.styles.forEach(preloadLateStyles, destination); // We only hoist importmaps that are configured through createResponse and that will
+ // always flush in the preamble. Generally we don't expect people to render them as
+ // tags when using React but if you do they are going to be treated like regular inline
+ // scripts and flush after other hoistables which is problematic
+ // bootstrap scripts should flush above script priority but these can only flush in the preamble
+ // so we elide the code here for performance
+
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0;
+}
+function writePostamble(destination, resumableState) {
+ if (resumableState.hasBody) {
+ writeChunk(destination, endChunkForTag('body'));
+ }
+
+ if (resumableState.hasHtml) {
+ writeChunk(destination, endChunkForTag('html'));
+ }
+}
+const arrayFirstOpenBracket = stringToPrecomputedChunk('[');
+const arraySubsequentOpenBracket = stringToPrecomputedChunk(',[');
+const arrayInterstitial = stringToPrecomputedChunk(',');
+const arrayCloseBracket = stringToPrecomputedChunk(']'); // This function writes a 2D array of strings to be embedded in javascript.
+// E.g.
+// [["JS_escaped_string1", "JS_escaped_string2"]]
+
+function writeStyleResourceDependenciesInJS(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInJS(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInJS(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInJS(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+}
+
+function writeStyleResourceDependencyInJS(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedPrecedence)));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInJS(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInJS(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeName)));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeValue)));
+} // This function writes a 2D array of strings to be embedded in an attribute
+// value and read with JSON.parse in ReactDOMServerExternalRuntime.js
+// E.g.
+// [["JSON_escaped_string1", "JSON_escaped_string2"]]
+
+
+function writeStyleResourceDependenciesInAttr(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInAttr(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInAttr(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInAttr(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+}
+
+function writeStyleResourceDependencyInAttr(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedPrecedence))));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInAttr(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInAttr(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeName))));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeValue))));
+}
+/**
+ * Resources
+ */
+
+
+const PENDING$1 = 0;
+const PRELOADED = 1;
+const PREAMBLE = 2;
+const LATE = 3;
+function createBoundaryResources() {
+ return {
+ styles: new Set(),
+ stylesheets: new Set()
+ };
+}
+function setCurrentlyRenderingBoundaryResourcesTarget(renderState, boundaryResources) {
+ renderState.boundaryResources = boundaryResources;
+}
+
+function getResourceKey(href) {
+ return href;
+}
+
+function getImageResourceKey(href, imageSrcSet, imageSizes) {
+ if (imageSrcSet) {
+ return imageSrcSet + '\n' + (imageSizes || '');
+ }
+
+ return href;
+}
+
+function prefetchDNS(href) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const key = getResourceKey(href);
+
+ if (!resumableState.dnsResources.hasOwnProperty(key)) {
+ resumableState.dnsResources[key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPrefetchDNSAsHeader(href), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this as resettable in case we are prerendering and postpone in the Shell
+ renderState.resets.dns[key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ // Encode as element
+ const resource = [];
+ pushLinkImpl(resource, {
+ href,
+ rel: 'dns-prefetch'
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preconnect(href, crossOrigin) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const bucket = crossOrigin === 'use-credentials' ? 'credentials' : typeof crossOrigin === 'string' ? 'anonymous' : 'default';
+ const key = getResourceKey(href);
+
+ if (!resumableState.connectResources[bucket].hasOwnProperty(key)) {
+ resumableState.connectResources[bucket][key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreconnectAsHeader(href, crossOrigin), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this in resettableState in case we are prerending and postpone in the Shell
+ renderState.resets.connect[bucket][key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ const resource = [];
+ pushLinkImpl(resource, {
+ rel: 'preconnect',
+ href,
+ crossOrigin
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preload(href, as, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (as && href) {
+ switch (as) {
+ case 'image':
+ {
+ let imageSrcSet, imageSizes, fetchPriority;
+
+ if (options) {
+ imageSrcSet = options.imageSrcSet;
+ imageSizes = options.imageSizes;
+ fetchPriority = options.fetchPriority;
+ }
+
+ const key = getImageResourceKey(href, imageSrcSet, imageSizes);
+
+ if (resumableState.imageResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resumableState.imageResources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && fetchPriority === 'high' && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit a preload as a header so we
+ // track this to make sure we don't reset it.
+ renderState.resets.image[key] = PRELOAD_NO_CREDS;
+
+ if (headers.highImagePreloads) {
+ headers.highImagePreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.highImagePreloads += header;
+ } else {
+ // If we don't have headers to write to we have to encode as elements to flush in the head
+ // When we have imageSrcSet the browser probably cannot load the right version from headers
+ // (this should be verified by testing). For now we assume these need to go in the head
+ // as elements even if headers are available.
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ // There is a bug in Safari where imageSrcSet is not respected on preload links
+ // so we omit the href here if we have imageSrcSet b/c safari will load the wrong image.
+ // This harms older browers that do not support imageSrcSet by making their preloads not work
+ // but this population is shrinking fast and is already small so we accept this tradeoff.
+ href: imageSrcSet ? undefined : href,
+ as
+ }, options));
+
+ if (fetchPriority === 'high') {
+ renderState.highImagePreloads.add(resource);
+ } else {
+ renderState.bulkPreloads.add(resource); // Stash the resource in case we need to promote it to higher priority
+ // when an img tag is rendered
+
+ renderState.preloads.images.set(key, resource);
+ }
+ }
+
+ break;
+ }
+
+ case 'style':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.styleResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.styleResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.stylesheets.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ break;
+ }
+
+ case 'script':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.scriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ renderState.preloads.scripts.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.scriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ break;
+ }
+
+ default:
+ {
+ const key = getResourceKey(href);
+ const hasAsType = resumableState.unknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.unknownResources[as] = resources;
+ }
+
+ resources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && as === 'font' && ( // We compute the header here because we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit this preload so we
+ // track it here to prevent it from being reset.
+ renderState.resets.font[key] = PRELOAD_NO_CREDS;
+
+ if (headers.fontPreloads) {
+ headers.fontPreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.fontPreloads += header;
+ } else {
+ // We either don't have headers or we are preloading something that does
+ // not warrant elevated priority so we encode as an element.
+ const resource = [];
+
+ const props = assign({
+ rel: 'preload',
+ href,
+ as
+ }, options);
+
+ pushLinkImpl(resource, props);
+
+ switch (as) {
+ case 'font':
+ renderState.fontPreloads.add(resource);
+ break;
+ // intentional fall through
+
+ default:
+ renderState.bulkPreloads.add(resource);
+ }
+ }
+ }
+ } // If we got this far we created a new resource
+
+
+ flushResources(request);
+ }
+}
+
+function preloadModule(href, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ const key = getResourceKey(href);
+ const as = options && typeof options.as === 'string' ? options.as : 'script';
+ let resource;
+
+ switch (as) {
+ case 'script':
+ {
+ if (resumableState.moduleScriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resource = [];
+ resumableState.moduleScriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.moduleScripts.set(key, resource);
+ break;
+ }
+
+ default:
+ {
+ const hasAsType = resumableState.moduleUnknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.moduleUnknownResources[as] = resources;
+ }
+
+ resource = [];
+ resources[key] = PRELOAD_NO_CREDS;
+ }
+ }
+
+ pushLinkImpl(resource, assign({
+ rel: 'modulepreload',
+ href
+ }, options));
+ renderState.bulkPreloads.add(resource); // If we got this far we created a new resource
+
+ flushResources(request);
+ }
+}
+
+function preinitStyle(href, precedence, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ precedence = precedence || 'default';
+ const key = getResourceKey(href);
+ let styleQueue = renderState.styles.get(precedence);
+ const hasKey = resumableState.styleResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.styleResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.styleResources[key] = EXISTS; // If this is the first time we've encountered this precedence we need
+ // to create a StyleQueue
+
+ if (!styleQueue) {
+ styleQueue = {
+ precedence: stringToChunk(escapeTextForBrowser(precedence)),
+ rules: [],
+ hrefs: [],
+ sheets: new Map()
+ };
+ renderState.styles.set(precedence, styleQueue);
+ }
+
+ const resource = {
+ state: PENDING$1,
+ props: assign({
+ rel: 'stylesheet',
+ href,
+ 'data-precedence': precedence
+ }, options)
+ };
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(resource.props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.stylesheets.get(key);
+
+ if (preloadResource && preloadResource.length > 0) {
+ // The Preload for this resource was created in this render pass and has not flushed yet so
+ // we need to clear it to avoid it flushing.
+ preloadResource.length = 0;
+ } else {
+ // Either the preload resource from this render already flushed in this render pass
+ // or the preload flushed in a prior pass (prerender). In either case we need to mark
+ // this resource as already having been preloaded.
+ resource.state = PRELOADED;
+ }
+ } // We add the newly created resource to our StyleQueue and if necessary
+ // track the resource with the currently rendering boundary
+
+
+ styleQueue.sheets.set(key, resource); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+ }
+}
+
+function preinitScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.scriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.scriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.scriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.scripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+}
+
+function preinitModuleScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.moduleScriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.moduleScriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.moduleScriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ type: 'module',
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.moduleScripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+} // This function is only safe to call at Request start time since it assumes
+// that each module has not already been preloaded. If we find a need to preload
+// scripts at any other point in time we will need to check whether the preload
+// already exists and not assume it
+
+
+function preloadBootstrapScriptOrModule(resumableState, renderState, href, props) {
+
+ const key = getResourceKey(href);
+ // used to preinit the resource. If a script can be preinited then it shouldn't
+ // be a bootstrap script/module and if it is a bootstrap script/module then it
+ // must not be safe to emit early. To avoid possibly allowing for preinits of
+ // bootstrap scripts/modules we occlude these keys.
+
+
+ resumableState.scriptResources[key] = EXISTS;
+ resumableState.moduleScriptResources[key] = EXISTS;
+ const resource = [];
+ pushLinkImpl(resource, props);
+ renderState.bootstrapScripts.add(resource);
+}
+
+function internalPreinitScript(resumableState, renderState, src, chunks) {
+ const key = getResourceKey(src);
+
+ if (!resumableState.scriptResources.hasOwnProperty(key)) {
+ const resource = chunks;
+ resumableState.scriptResources[key] = EXISTS;
+ renderState.scripts.add(resource);
+ }
+
+ return;
+}
+
+function preloadAsStylePropsFromProps(href, props) {
+ return {
+ rel: 'preload',
+ as: 'style',
+ href: href,
+ crossOrigin: props.crossOrigin,
+ fetchPriority: props.fetchPriority,
+ integrity: props.integrity,
+ media: props.media,
+ hrefLang: props.hrefLang,
+ referrerPolicy: props.referrerPolicy
+ };
+}
+
+function stylesheetPropsFromRawProps(rawProps) {
+ return assign({}, rawProps, {
+ 'data-precedence': rawProps.precedence,
+ precedence: null
+ });
+}
+
+function adoptPreloadCredentials(target, preloadState) {
+ if (target.crossOrigin == null) target.crossOrigin = preloadState[0];
+ if (target.integrity == null) target.integrity = preloadState[1];
+}
+
+function getPrefetchDNSAsHeader(href) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ return "<" + escapedHref + ">; rel=dns-prefetch";
+}
+
+function getPreconnectAsHeader(href, crossOrigin) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ let value = "<" + escapedHref + ">; rel=preconnect";
+
+ if (typeof crossOrigin === 'string') {
+ const escapedCrossOrigin = escapeStringForLinkHeaderQuotedParamValueContext(crossOrigin);
+ value += "; crossorigin=\"" + escapedCrossOrigin + "\"";
+ }
+
+ return value;
+}
+
+function getPreloadAsHeader(href, as, params) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ const escapedAs = escapeStringForLinkHeaderQuotedParamValueContext(as);
+ let value = "<" + escapedHref + ">; rel=preload; as=\"" + escapedAs + "\"";
+
+ for (const paramName in params) {
+ if (hasOwnProperty.call(params, paramName)) {
+ const paramValue = params[paramName];
+
+ if (typeof paramValue === 'string') {
+ value += "; " + paramName.toLowerCase() + "=\"" + escapeStringForLinkHeaderQuotedParamValueContext(paramValue) + "\"";
+ }
+ }
+ }
+
+ return value;
+}
+
+function getStylesheetPreloadAsHeader(stylesheet) {
+ const props = stylesheet.props;
+ const preloadOptions = {
+ crossOrigin: props.crossOrigin,
+ integrity: props.integrity,
+ nonce: props.nonce,
+ type: props.type,
+ fetchPriority: props.fetchPriority,
+ referrerPolicy: props.referrerPolicy,
+ media: props.media
+ };
+ return getPreloadAsHeader(props.href, 'style', preloadOptions);
+} // This escaping function is only safe to use for href values being written into
+// a "Link" header in between `<` and `>` characters. The primary concern with the href is
+// to escape the bounding characters as well as new lines. This is unsafe to use in any other
+// context
+
+
+const regexForHrefInLinkHeaderURLContext = /[<>\r\n]/g;
+
+function escapeHrefForLinkHeaderURLContext(hrefInput) {
+
+ const coercedHref = '' + hrefInput;
+ return coercedHref.replace(regexForHrefInLinkHeaderURLContext, escapeHrefForLinkHeaderURLContextReplacer);
+}
+
+function escapeHrefForLinkHeaderURLContextReplacer(match) {
+ switch (match) {
+ case '<':
+ return '%3C';
+
+ case '>':
+ return '%3E';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+} // This escaping function is only safe to use for quoted param values in an HTTP header.
+// It is unsafe to use for any value not inside quote marks in parater value position.
+
+
+const regexForLinkHeaderQuotedParamValueContext = /["';,\r\n]/g;
+
+function escapeStringForLinkHeaderQuotedParamValueContext(value, name) {
+
+ const coerced = '' + value;
+ return coerced.replace(regexForLinkHeaderQuotedParamValueContext, escapeStringForLinkHeaderQuotedParamValueContextReplacer);
+}
+
+function escapeStringForLinkHeaderQuotedParamValueContextReplacer(match) {
+ switch (match) {
+ case '"':
+ return '%22';
+
+ case "'":
+ return '%27';
+
+ case ';':
+ return '%3B';
+
+ case ',':
+ return '%2C';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+}
+
+function hoistStyleQueueDependency(styleQueue) {
+ this.styles.add(styleQueue);
+}
+
+function hoistStylesheetDependency(stylesheet) {
+ this.stylesheets.add(stylesheet);
+}
+
+function hoistResources(renderState, source) {
+ const currentBoundaryResources = renderState.boundaryResources;
+
+ if (currentBoundaryResources) {
+ source.styles.forEach(hoistStyleQueueDependency, currentBoundaryResources);
+ source.stylesheets.forEach(hoistStylesheetDependency, currentBoundaryResources);
+ }
+} // This function is called at various times depending on whether we are rendering
+// or prerendering. In this implementation we only actually emit headers once and
+// subsequent calls are ignored. We track whether the request has a completed shell
+// to determine whether we will follow headers with a flush including stylesheets.
+// In the context of prerrender we don't have a completed shell when the request finishes
+// with a postpone in the shell. In the context of a render we don't have a completed shell
+// if this is called before the shell finishes rendering which usually will happen anytime
+// anything suspends in the shell.
+
+function emitEarlyPreloads(renderState, resumableState, shellComplete) {
+ const onHeaders = renderState.onHeaders;
+
+ if (onHeaders) {
+ const headers = renderState.headers;
+
+ if (headers) {
+ let linkHeader = headers.preconnects;
+
+ if (headers.fontPreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.fontPreloads;
+ }
+
+ if (headers.highImagePreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.highImagePreloads;
+ }
+
+ if (!shellComplete) {
+ // We use raw iterators because we want to be able to halt iteration
+ // We could refactor renderState to store these dually in arrays to
+ // make this more efficient at the cost of additional memory and
+ // write overhead. However this code only runs once per request so
+ // for now I consider this sufficient.
+ const queueIter = renderState.styles.values();
+
+ outer: for (let queueStep = queueIter.next(); headers.remainingCapacity > 0 && !queueStep.done; queueStep = queueIter.next()) {
+ const sheets = queueStep.value.sheets;
+ const sheetIter = sheets.values();
+
+ for (let sheetStep = sheetIter.next(); headers.remainingCapacity > 0 && !sheetStep.done; sheetStep = sheetIter.next()) {
+ const sheet = sheetStep.value;
+ const props = sheet.props;
+ const key = getResourceKey(props.href);
+ const header = getStylesheetPreloadAsHeader(sheet); // We mutate the capacity b/c we don't want to keep checking if later headers will fit.
+ // This means that a particularly long header might close out the header queue where later
+ // headers could still fit. We could in the future alter the behavior here based on prerender vs render
+ // since during prerender we aren't as concerned with pure runtime performance.
+
+ if ((headers.remainingCapacity -= header.length) >= 2) {
+ renderState.resets.style[key] = PRELOAD_NO_CREDS;
+
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += header; // We already track that the resource exists in resumableState however
+ // if the resumableState resets because we postponed in the shell
+ // which is what is happening in this branch if we are prerendering
+ // then we will end up resetting the resumableState. When it resets we
+ // want to record the fact that this stylesheet was already preloaded
+
+ renderState.resets.style[key] = typeof props.crossOrigin === 'string' || typeof props.integrity === 'string' ? [props.crossOrigin, props.integrity] : PRELOAD_NO_CREDS;
+ } else {
+ break outer;
+ }
+ }
+ }
+ }
+
+ if (linkHeader) {
+ onHeaders({
+ Link: linkHeader
+ });
+ } else {
+ // We still call this with no headers because a user may be using it as a signal that
+ // it React will not provide any headers
+ onHeaders({});
+ }
+
+ renderState.headers = null;
+ return;
+ }
+ }
+}
+const NotPendingTransition = NotPending;
+
+const requestStorage = new async_hooks.AsyncLocalStorage();
+
+// ATTENTION
+// When adding new symbols to this file,
+// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
+// The Symbol used to tag the ReactElement-like types.
+const REACT_ELEMENT_TYPE = Symbol.for('react.element');
+const REACT_PORTAL_TYPE = Symbol.for('react.portal');
+const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
+const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
+const REACT_PROFILER_TYPE = Symbol.for('react.profiler');
+const REACT_PROVIDER_TYPE = Symbol.for('react.provider');
+const REACT_CONTEXT_TYPE = Symbol.for('react.context');
+const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
+const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
+const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
+const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
+const REACT_MEMO_TYPE = Symbol.for('react.memo');
+const REACT_LAZY_TYPE = Symbol.for('react.lazy');
+const REACT_SCOPE_TYPE = Symbol.for('react.scope');
+const REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');
+const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
+const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');
+const REACT_CACHE_TYPE = Symbol.for('react.cache');
+const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value');
+const REACT_MEMO_CACHE_SENTINEL = Symbol.for('react.memo_cache_sentinel');
+const REACT_POSTPONE_TYPE = Symbol.for('react.postpone');
+const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
+const FAUX_ITERATOR_SYMBOL = '@@iterator';
+function getIteratorFn(maybeIterable) {
+ if (maybeIterable === null || typeof maybeIterable !== 'object') {
+ return null;
+ }
+
+ const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
+
+ if (typeof maybeIterator === 'function') {
+ return maybeIterator;
+ }
+
+ return null;
+}
+
+function getWrappedName(outerType, innerType, wrapperName) {
+ const displayName = outerType.displayName;
+
+ if (displayName) {
+ return displayName;
+ }
+
+ const functionName = innerType.displayName || innerType.name || '';
+ return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName;
+} // Keep in sync with react-reconciler/getComponentNameFromFiber
+
+
+function getContextName(type) {
+ return type.displayName || 'Context';
+} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+
+
+function getComponentNameFromType(type) {
+ if (type == null) {
+ // Host root, text node or just invalid type.
+ return null;
+ }
+
+ if (typeof type === 'function') {
+ return type.displayName || type.name || null;
+ }
+
+ if (typeof type === 'string') {
+ return type;
+ }
+
+ switch (type) {
+ case REACT_FRAGMENT_TYPE:
+ return 'Fragment';
+
+ case REACT_PORTAL_TYPE:
+ return 'Portal';
+
+ case REACT_PROFILER_TYPE:
+ return 'Profiler';
+
+ case REACT_STRICT_MODE_TYPE:
+ return 'StrictMode';
+
+ case REACT_SUSPENSE_TYPE:
+ return 'Suspense';
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ return 'SuspenseList';
+
+ case REACT_CACHE_TYPE:
+ {
+ return 'Cache';
+ }
+
+ }
+
+ if (typeof type === 'object') {
+ switch (type.$$typeof) {
+ case REACT_CONTEXT_TYPE:
+ const context = type;
+ return getContextName(context) + '.Consumer';
+
+ case REACT_PROVIDER_TYPE:
+ const provider = type;
+ return getContextName(provider._context) + '.Provider';
+
+ case REACT_FORWARD_REF_TYPE:
+ return getWrappedName(type, type.render, 'ForwardRef');
+
+ case REACT_MEMO_TYPE:
+ const outerName = type.displayName || null;
+
+ if (outerName !== null) {
+ return outerName;
+ }
+
+ return getComponentNameFromType(type.type) || 'Memo';
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyComponent = type;
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+
+ try {
+ return getComponentNameFromType(init(payload));
+ } catch (x) {
+ return null;
+ }
+ }
+
+ case REACT_SERVER_CONTEXT_TYPE:
+ {
+ const context2 = type;
+ return (context2.displayName || context2._globalName) + '.Provider';
+ }
+
+ }
+ }
+
+ return null;
+}
+
+const emptyContextObject = {};
+
+function getMaskedContext(type, unmaskedContext) {
+ {
+ const contextTypes = type.contextTypes;
+
+ if (!contextTypes) {
+ return emptyContextObject;
+ }
+
+ const context = {};
+
+ for (const key in contextTypes) {
+ context[key] = unmaskedContext[key];
+ }
+
+ return context;
+ }
+}
+function processChildContext(instance, type, parentContext, childContextTypes) {
+ {
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
+ if (typeof instance.getChildContext !== 'function') {
+
+ return parentContext;
+ }
+
+ const childContext = instance.getChildContext();
+
+ for (const contextKey in childContext) {
+ if (!(contextKey in childContextTypes)) {
+ throw new Error((getComponentNameFromType(type) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes.");
+ }
+ }
+
+ return assign({}, parentContext, childContext);
+ }
+}
+
+// Forming a reverse tree.
+// The structure of a context snapshot is an implementation of this file.
+// Currently, it's implemented as tracking the current active node.
+
+
+const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
+// This global (actually thread local) state represents what state all those "current",
+// fields are currently in.
+
+let currentActiveSnapshot = null;
+
+function popNode(prev) {
+ {
+ prev.context._currentValue = prev.parentValue;
+ }
+}
+
+function pushNode(next) {
+ {
+ next.context._currentValue = next.value;
+ }
+}
+
+function popToNearestCommonAncestor(prev, next) {
+ if (prev === next) ; else {
+ popNode(prev);
+ const parentPrev = prev.parent;
+ const parentNext = next.parent;
+
+ if (parentPrev === null) {
+ if (parentNext !== null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+ } else {
+ if (parentNext === null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+
+ popToNearestCommonAncestor(parentPrev, parentNext);
+ } // On the way back, we push the new ones that weren't common.
+
+
+ pushNode(next);
+ }
+}
+
+function popAllPrevious(prev) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev !== null) {
+ popAllPrevious(parentPrev);
+ }
+}
+
+function pushAllNext(next) {
+ const parentNext = next.parent;
+
+ if (parentNext !== null) {
+ pushAllNext(parentNext);
+ }
+
+ pushNode(next);
+}
+
+function popPreviousToCommonLevel(prev, next) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (parentPrev.depth === next.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(parentPrev, next);
+ } else {
+ // We must still be deeper.
+ popPreviousToCommonLevel(parentPrev, next);
+ }
+}
+
+function popNextToCommonLevel(prev, next) {
+ const parentNext = next.parent;
+
+ if (parentNext === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (prev.depth === parentNext.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(prev, parentNext);
+ } else {
+ // We must still be deeper.
+ popNextToCommonLevel(prev, parentNext);
+ }
+
+ pushNode(next);
+} // Perform context switching to the new snapshot.
+// To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
+// updating all the context's current values. That way reads, always just read the current value.
+// At the cost of updating contexts even if they're never read by this subtree.
+
+
+function switchContext(newSnapshot) {
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
+ // We also need to update any new contexts that are now on the stack with the deepest value.
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
+ // for that. Therefore this algorithm is recursive.
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
+ // 3) Then we reapply new contexts on the way back up the stack.
+ const prev = currentActiveSnapshot;
+ const next = newSnapshot;
+
+ if (prev !== next) {
+ if (prev === null) {
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
+ pushAllNext(next);
+ } else if (next === null) {
+ popAllPrevious(prev);
+ } else if (prev.depth === next.depth) {
+ popToNearestCommonAncestor(prev, next);
+ } else if (prev.depth > next.depth) {
+ popPreviousToCommonLevel(prev, next);
+ } else {
+ popNextToCommonLevel(prev, next);
+ }
+
+ currentActiveSnapshot = next;
+ }
+}
+function pushProvider(context, nextValue) {
+ let prevValue;
+
+ {
+ prevValue = context._currentValue;
+ context._currentValue = nextValue;
+ }
+
+ const prevNode = currentActiveSnapshot;
+ const newNode = {
+ parent: prevNode,
+ depth: prevNode === null ? 0 : prevNode.depth + 1,
+ context: context,
+ parentValue: prevValue,
+ value: nextValue
+ };
+ currentActiveSnapshot = newNode;
+ return newNode;
+}
+function popProvider(context) {
+ const prevSnapshot = currentActiveSnapshot;
+
+ if (prevSnapshot === null) {
+ throw new Error('Tried to pop a Context at the root of the app. This is a bug in React.');
+ }
+
+ {
+ const value = prevSnapshot.parentValue;
+
+ if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) {
+ prevSnapshot.context._currentValue = prevSnapshot.context._defaultValue;
+ } else {
+ prevSnapshot.context._currentValue = value;
+ }
+ }
+
+ return currentActiveSnapshot = prevSnapshot.parent;
+}
+function getActiveContext() {
+ return currentActiveSnapshot;
+}
+function readContext$1(context) {
+ const value = context._currentValue ;
+ return value;
+}
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ *
+ * Note that this module is currently shared and assumed to be stateless.
+ * If this becomes an actual Map, that will break.
+ */
+function get(key) {
+ return key._reactInternals;
+}
+function set(key, value) {
+ key._reactInternals = value;
+}
+
+const classComponentUpdater = {
+ isMounted(inst) {
+ return false;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueSetState(inst, payload, callback) {
+ const internals = get(inst);
+
+ if (internals.queue === null) ; else {
+ internals.queue.push(payload);
+ }
+ },
+
+ enqueueReplaceState(inst, payload, callback) {
+ const internals = get(inst);
+ internals.replace = true;
+ internals.queue = [payload];
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueForceUpdate(inst, callback) {
+ }
+
+};
+
+function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) {
+ const partialState = getDerivedStateFromProps(nextProps, prevState);
+
+
+ const newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);
+ return newState;
+}
+
+function constructClassInstance(ctor, props, maskedLegacyContext) {
+ let context = emptyContextObject;
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ context = readContext$1(contextType);
+ } else {
+ context = maskedLegacyContext;
+ }
+
+ const instance = new ctor(props, context);
+
+ return instance;
+}
+
+function callComponentWillMount(type, instance) {
+ const oldState = instance.state;
+
+ if (typeof instance.componentWillMount === 'function') {
+
+ instance.componentWillMount();
+ }
+
+ if (typeof instance.UNSAFE_componentWillMount === 'function') {
+ instance.UNSAFE_componentWillMount();
+ }
+
+ if (oldState !== instance.state) {
+
+ classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
+ }
+}
+
+function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) {
+ if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
+ const oldQueue = internalInstance.queue;
+ const oldReplace = internalInstance.replace;
+ internalInstance.queue = null;
+ internalInstance.replace = false;
+
+ if (oldReplace && oldQueue.length === 1) {
+ inst.state = oldQueue[0];
+ } else {
+ let nextState = oldReplace ? oldQueue[0] : inst.state;
+ let dontMutate = true;
+
+ for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
+ const partial = oldQueue[i];
+ const partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial;
+
+ if (partialState != null) {
+ if (dontMutate) {
+ dontMutate = false;
+ nextState = assign({}, nextState, partialState);
+ } else {
+ assign(nextState, partialState);
+ }
+ }
+ }
+
+ inst.state = nextState;
+ }
+ } else {
+ internalInstance.queue = null;
+ }
+} // Invokes the mount life-cycles on a previously never rendered instance.
+
+
+function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) {
+
+ const initialState = instance.state !== undefined ? instance.state : null;
+ instance.updater = classComponentUpdater;
+ instance.props = newProps;
+ instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway.
+ // The internal instance will be used to manage updates that happen during this mount.
+
+ const internalInstance = {
+ queue: [],
+ replace: false
+ };
+ set(instance, internalInstance);
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ instance.context = readContext$1(contextType);
+ } else {
+ instance.context = maskedLegacyContext;
+ }
+
+ const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
+
+ if (typeof getDerivedStateFromProps === 'function') {
+ instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps);
+ } // In order to support react-lifecycles-compat polyfilled components,
+ // Unsafe lifecycles should not be invoked for components using the new APIs.
+
+
+ if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
+ callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's
+ // process them now.
+
+ processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext);
+ }
+}
+
+// Ids are base 32 strings whose binary representation corresponds to the
+// position of a node in a tree.
+// Every time the tree forks into multiple children, we add additional bits to
+// the left of the sequence that represent the position of the child within the
+// current level of children.
+//
+// 00101 00010001011010101
+// ╰─┬─╯ ╰───────┬───────╯
+// Fork 5 of 20 Parent id
+//
+// The leading 0s are important. In the above example, you only need 3 bits to
+// represent slot 5. However, you need 5 bits to represent all the forks at
+// the current level, so we must account for the empty bits at the end.
+//
+// For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise,
+// the zeroth id at a level would be indistinguishable from its parent.
+//
+// If a node has only one child, and does not materialize an id (i.e. does not
+// contain a useId hook), then we don't need to allocate any space in the
+// sequence. It's treated as a transparent indirection. For example, these two
+// trees produce the same ids:
+//
+// <> <>
+//
+//
+// >
+//
+// >
+//
+// However, we cannot skip any node that materializes an id. Otherwise, a parent
+// id that does not fork would be indistinguishable from its child id. For
+// example, this tree does not fork, but the parent and child must have
+// different ids.
+//
+//
+//
+//
+//
+// To handle this scenario, every time we materialize an id, we allocate a
+// new level with a single slot. You can think of this as a fork with only one
+// prong, or an array of children with length 1.
+//
+// It's possible for the size of the sequence to exceed 32 bits, the max
+// size for bitwise operations. When this happens, we make more room by
+// converting the right part of the id to a string and storing it in an overflow
+// variable. We use a base 32 string representation, because 32 is the largest
+// power of 2 that is supported by toString(). We want the base to be large so
+// that the resulting ids are compact, and we want the base to be a power of 2
+// because every log2(base) bits corresponds to a single character, i.e. every
+// log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without
+// affecting the final result.
+const emptyTreeContext = {
+ id: 1,
+ overflow: ''
+};
+function getTreeId(context) {
+ const overflow = context.overflow;
+ const idWithLeadingBit = context.id;
+ const id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);
+ return id.toString(32) + overflow;
+}
+function pushTreeContext(baseContext, totalChildren, index) {
+ const baseIdWithLeadingBit = baseContext.id;
+ const baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part
+ // of the id; we use it to account for leading 0s.
+
+ const baseLength = getBitLength(baseIdWithLeadingBit) - 1;
+ const baseId = baseIdWithLeadingBit & ~(1 << baseLength);
+ const slot = index + 1;
+ const length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into
+ // consideration the leading 1 we use to mark the end of the sequence.
+
+ if (length > 30) {
+ // We overflowed the bitwise-safe range. Fall back to slower algorithm.
+ // This branch assumes the length of the base id is greater than 5; it won't
+ // work for smaller ids, because you need 5 bits per character.
+ //
+ // We encode the id in multiple steps: first the base id, then the
+ // remaining digits.
+ //
+ // Each 5 bit sequence corresponds to a single base 32 character. So for
+ // example, if the current id is 23 bits long, we can convert 20 of those
+ // bits into a string of 4 characters, with 3 bits left over.
+ //
+ // First calculate how many bits in the base id represent a complete
+ // sequence of characters.
+ const numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.
+
+ const newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.
+
+ const newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.
+
+ const restOfBaseId = baseId >> numberOfOverflowBits;
+ const restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because
+ // we made more room, this time it won't overflow.
+
+ const restOfLength = getBitLength(totalChildren) + restOfBaseLength;
+ const restOfNewBits = slot << restOfBaseLength;
+ const id = restOfNewBits | restOfBaseId;
+ const overflow = newOverflow + baseOverflow;
+ return {
+ id: 1 << restOfLength | id,
+ overflow
+ };
+ } else {
+ // Normal path
+ const newBits = slot << baseLength;
+ const id = newBits | baseId;
+ const overflow = baseOverflow;
+ return {
+ id: 1 << length | id,
+ overflow
+ };
+ }
+}
+
+function getBitLength(number) {
+ return 32 - clz32(number);
+}
+
+function getLeadingBit(id) {
+ return 1 << getBitLength(id) - 1;
+} // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback.
+
+
+const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.
+// Based on:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+const log = Math.log;
+const LN2 = Math.LN2;
+
+function clz32Fallback(x) {
+ const asUint = x >>> 0;
+
+ if (asUint === 0) {
+ return 32;
+ }
+
+ return 31 - (log(asUint) / LN2 | 0) | 0;
+}
+
+// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
+// changes to one module should be reflected in the others.
+// TODO: Rename this module and the corresponding Fiber one to "Thenable"
+// instead of "Wakeable". Or some other more appropriate name.
+// An error that is thrown (e.g. by `use`) to trigger Suspense. If we
+// detect this is caught by userspace, we'll log a warning in development.
+const SuspenseException = new Error("Suspense Exception: This is not a real error! It's an implementation " + 'detail of `use` to interrupt the current render. You must either ' + 'rethrow it immediately, or move the `use` call outside of the ' + '`try/catch` block. Capturing without rethrowing will lead to ' + 'unexpected behavior.\n\n' + 'To handle async errors, wrap your component in an error boundary, or ' + "call the promise's `.catch` method and pass the result to `use`");
+function createThenableState() {
+ // The ThenableState is created the first time a component suspends. If it
+ // suspends again, we'll reuse the same state.
+ return [];
+}
+
+function noop$2() {}
+
+function trackUsedThenable(thenableState, thenable, index) {
+ const previous = thenableState[index];
+
+ if (previous === undefined) {
+ thenableState.push(thenable);
+ } else {
+ if (previous !== thenable) {
+ // Reuse the previous thenable, and drop the new one. We can assume
+ // they represent the same value, because components are idempotent.
+ // Avoid an unhandled rejection errors for the Promises that we'll
+ // intentionally ignore.
+ thenable.then(noop$2, noop$2);
+ thenable = previous;
+ }
+ } // We use an expando to track the status and result of a thenable so that we
+ // can synchronously unwrap the value. Think of this as an extension of the
+ // Promise API, or a custom interface that is a superset of Thenable.
+ //
+ // If the thenable doesn't have a status, set it to "pending" and attach
+ // a listener that will update its status and result when it resolves.
+
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledValue = thenable.value;
+ return fulfilledValue;
+ }
+
+ case 'rejected':
+ {
+ const rejectedError = thenable.reason;
+ throw rejectedError;
+ }
+
+ default:
+ {
+ if (typeof thenable.status === 'string') ; else {
+ const pendingThenable = thenable;
+ pendingThenable.status = 'pending';
+ pendingThenable.then(fulfilledValue => {
+ if (thenable.status === 'pending') {
+ const fulfilledThenable = thenable;
+ fulfilledThenable.status = 'fulfilled';
+ fulfilledThenable.value = fulfilledValue;
+ }
+ }, error => {
+ if (thenable.status === 'pending') {
+ const rejectedThenable = thenable;
+ rejectedThenable.status = 'rejected';
+ rejectedThenable.reason = error;
+ }
+ }); // Check one more time in case the thenable resolved synchronously
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledThenable = thenable;
+ return fulfilledThenable.value;
+ }
+
+ case 'rejected':
+ {
+ const rejectedThenable = thenable;
+ throw rejectedThenable.reason;
+ }
+ }
+ } // Suspend.
+ //
+ // Throwing here is an implementation detail that allows us to unwind the
+ // call stack. But we shouldn't allow it to leak into userspace. Throw an
+ // opaque placeholder value instead of the actual thenable. If it doesn't
+ // get captured by the work loop, log a warning, because that means
+ // something in userspace must have caught it.
+
+
+ suspendedThenable = thenable;
+ throw SuspenseException;
+ }
+ }
+} // This is used to track the actual thenable that suspended so it can be
+// passed to the rest of the Suspense implementation — which, for historical
+// reasons, expects to receive a thenable.
+
+let suspendedThenable = null;
+function getSuspendedThenable() {
+ // This is called right after `use` suspends by throwing an exception. `use`
+ // throws an opaque value instead of the thenable itself so that it can't be
+ // caught in userspace. Then the work loop accesses the actual thenable using
+ // this function.
+ if (suspendedThenable === null) {
+ throw new Error('Expected a suspended thenable. This is a bug in React. Please file ' + 'an issue.');
+ }
+
+ const thenable = suspendedThenable;
+ suspendedThenable = null;
+ return thenable;
+}
+
+/**
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+ */
+function is(x, y) {
+ return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
+ ;
+}
+
+const objectIs = // $FlowFixMe[method-unbinding]
+typeof Object.is === 'function' ? Object.is : is;
+
+let currentlyRenderingComponent = null;
+let currentlyRenderingTask = null;
+let currentlyRenderingRequest = null;
+let currentlyRenderingKeyPath = null;
+let firstWorkInProgressHook = null;
+let workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook
+
+let isReRender = false; // Whether an update was scheduled during the currently executing render pass.
+
+let didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component
+
+let localIdCounter = 0; // Chunks that should be pushed to the stream once the component
+// finishes rendering.
+// Counts the number of useFormState calls in this component
+
+let formStateCounter = 0; // The index of the useFormState hook that matches the one passed in at the
+// root during an MPA navigation, if any.
+
+let formStateMatchingIndex = -1; // Counts the number of use(thenable) calls in this component
+
+let thenableIndexCounter = 0;
+let thenableState = null; // Lazily created map of render-phase updates
+
+let renderPhaseUpdates = null; // Counter to prevent infinite loops.
+
+let numberOfReRenders = 0;
+const RE_RENDER_LIMIT = 25;
+
+function resolveCurrentlyRenderingComponent() {
+ if (currentlyRenderingComponent === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + '2. You might be breaking the Rules of Hooks\n' + '3. You might have more than one copy of React in the same app\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.');
+ }
+
+ return currentlyRenderingComponent;
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+
+ return false;
+ }
+
+
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ if (objectIs(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+function createHook() {
+ if (numberOfReRenders > 0) {
+ throw new Error('Rendered more hooks than during the previous render');
+ }
+
+ return {
+ memoizedState: null,
+ queue: null,
+ next: null
+ };
+}
+
+function createWorkInProgressHook() {
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ if (firstWorkInProgressHook === null) {
+ isReRender = false;
+ firstWorkInProgressHook = workInProgressHook = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = firstWorkInProgressHook;
+ }
+ } else {
+ if (workInProgressHook.next === null) {
+ isReRender = false; // Append to the end of the list
+
+ workInProgressHook = workInProgressHook.next = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = workInProgressHook.next;
+ }
+ }
+
+ return workInProgressHook;
+}
+
+function prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState) {
+ currentlyRenderingComponent = componentIdentity;
+ currentlyRenderingTask = task;
+ currentlyRenderingRequest = request;
+ currentlyRenderingKeyPath = keyPath;
+ // didScheduleRenderPhaseUpdate = false;
+ // firstWorkInProgressHook = null;
+ // numberOfReRenders = 0;
+ // renderPhaseUpdates = null;
+ // workInProgressHook = null;
+
+
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ thenableState = prevThenableState;
+}
+function finishHooks(Component, props, children, refOrContext) {
+ // This must be called after every function component to prevent hooks from
+ // being used in classes.
+ while (didScheduleRenderPhaseUpdate) {
+ // Updates were scheduled during the render phase. They are stored in
+ // the `renderPhaseUpdates` map. Call the component again, reusing the
+ // work-in-progress hooks and applying the additional updates on top. Keep
+ // restarting until no more updates are scheduled.
+ didScheduleRenderPhaseUpdate = false;
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ numberOfReRenders += 1; // Start over from the beginning of the list
+
+ workInProgressHook = null;
+ children = Component(props, refOrContext);
+ }
+
+ resetHooksState();
+ return children;
+}
+function getThenableStateAfterSuspending() {
+ const state = thenableState;
+ thenableState = null;
+ return state;
+}
+function checkDidRenderIdHook() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ const didRenderIdHook = localIdCounter !== 0;
+ return didRenderIdHook;
+}
+function getFormStateCount() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateCounter;
+}
+function getFormStateMatchingIndex() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateMatchingIndex;
+} // Reset the internal hooks state if an error occurs while rendering a component
+
+function resetHooksState() {
+
+ currentlyRenderingComponent = null;
+ currentlyRenderingTask = null;
+ currentlyRenderingRequest = null;
+ currentlyRenderingKeyPath = null;
+ didScheduleRenderPhaseUpdate = false;
+ firstWorkInProgressHook = null;
+ numberOfReRenders = 0;
+ renderPhaseUpdates = null;
+ workInProgressHook = null;
+}
+
+function readContext(context) {
+
+ return readContext$1(context);
+}
+
+function useContext(context) {
+
+ resolveCurrentlyRenderingComponent();
+ return readContext$1(context);
+}
+
+function basicStateReducer(state, action) {
+ // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
+ return typeof action === 'function' ? action(state) : action;
+}
+
+function useState(initialState) {
+
+ return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers
+ initialState);
+}
+function useReducer(reducer, initialArg, init) {
+
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+
+ if (isReRender) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ // current hook.
+ const queue = workInProgressHook.queue;
+ const dispatch = queue.dispatch;
+
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate !== undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.delete(queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ let newState = workInProgressHook.memoizedState;
+ let update = firstRenderPhaseUpdate;
+
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ const action = update.action;
+
+ newState = reducer(newState, action);
+
+
+ update = update.next;
+ } while (update !== null); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ workInProgressHook.memoizedState = newState;
+ return [newState, dispatch];
+ }
+ } // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ return [workInProgressHook.memoizedState, dispatch];
+ } else {
+
+ let initialState;
+
+ if (reducer === basicStateReducer) {
+ // Special case for `useState`.
+ initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
+ } else {
+ initialState = init !== undefined ? init(initialArg) : initialArg;
+ }
+
+
+ workInProgressHook.memoizedState = initialState; // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ const queue = workInProgressHook.queue = {
+ last: null,
+ dispatch: null
+ };
+ const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ return [workInProgressHook.memoizedState, dispatch];
+ }
+}
+
+function useMemo(nextCreate, deps) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const nextDeps = deps === undefined ? null : deps;
+
+ if (workInProgressHook !== null) {
+ const prevState = workInProgressHook.memoizedState;
+
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ const prevDeps = prevState[1];
+
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ }
+
+ const nextValue = nextCreate();
+
+
+ workInProgressHook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function useRef(initialValue) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const previousRef = workInProgressHook.memoizedState;
+
+ if (previousRef === null) {
+ const ref = {
+ current: initialValue
+ };
+
+
+ workInProgressHook.memoizedState = ref;
+ return ref;
+ } else {
+ return previousRef;
+ }
+}
+
+function dispatchAction(componentIdentity, queue, action) {
+ if (numberOfReRenders >= RE_RENDER_LIMIT) {
+ throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.');
+ }
+
+ if (componentIdentity === currentlyRenderingComponent) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ const update = {
+ action,
+ next: null
+ };
+
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate === undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+
+ lastRenderPhaseUpdate.next = update;
+ }
+ }
+}
+
+function useCallback(callback, deps) {
+ return useMemo(() => callback, deps);
+}
+
+function throwOnUseEffectEventCall() {
+ throw new Error("A function wrapped in useEffectEvent can't be called during rendering.");
+}
+
+function useEffectEvent(callback) {
+ // $FlowIgnore[incompatible-return]
+ return throwOnUseEffectEventCall;
+}
+
+function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
+ if (getServerSnapshot === undefined) {
+ throw new Error('Missing getServerSnapshot, which is required for ' + 'server-rendered content. Will revert to client rendering.');
+ }
+
+ return getServerSnapshot();
+}
+
+function useDeferredValue(value, initialValue) {
+ resolveCurrentlyRenderingComponent();
+
+ {
+ return initialValue !== undefined ? initialValue : value;
+ }
+}
+
+function unsupportedStartTransition() {
+ throw new Error('startTransition cannot be called during server rendering.');
+}
+
+function useTransition() {
+ resolveCurrentlyRenderingComponent();
+ return [false, unsupportedStartTransition];
+}
+
+function useHostTransitionStatus() {
+ resolveCurrentlyRenderingComponent();
+ return NotPendingTransition;
+}
+
+function unsupportedSetOptimisticState() {
+ throw new Error('Cannot update optimistic state while rendering.');
+}
+
+function useOptimistic(passthrough, reducer) {
+ resolveCurrentlyRenderingComponent();
+ return [passthrough, unsupportedSetOptimisticState];
+}
+
+function createPostbackFormStateKey(permalink, componentKeyPath, hookIndex) {
+ if (permalink !== undefined) {
+ // Don't bother to hash a permalink-based key since it's already short.
+ return 'p' + permalink;
+ } else {
+ // Append a node to the key path that represents the form state hook.
+ const keyPath = [componentKeyPath, null, hookIndex]; // Key paths are hashed to reduce the size. It does not need to be secure,
+ // and it's more important that it's fast than that it's completely
+ // collision-free.
+
+ const keyPathHash = createFastHash(JSON.stringify(keyPath));
+ return 'k' + keyPathHash;
+ }
+}
+
+function useFormState(action, initialState, permalink) {
+ resolveCurrentlyRenderingComponent(); // Count the number of useFormState hooks per component. We also use this to
+ // track the position of this useFormState hook relative to the other ones in
+ // this component, so we can generate a unique key for each one.
+
+ const formStateHookIndex = formStateCounter++;
+ const request = currentlyRenderingRequest; // $FlowIgnore[prop-missing]
+
+ const formAction = action.$$FORM_ACTION;
+
+ if (typeof formAction === 'function') {
+ // This is a server action. These have additional features to enable
+ // MPA-style form submissions with progressive enhancement.
+ // TODO: If the same permalink is passed to multiple useFormStates, and
+ // they all have the same action signature, Fizz will pass the postback
+ // state to all of them. We should probably only pass it to the first one,
+ // and/or warn.
+ // The key is lazily generated and deduped so the that the keypath doesn't
+ // get JSON.stringify-ed unnecessarily, and at most once.
+ let nextPostbackStateKey = null; // Determine the current form state. If we received state during an MPA form
+ // submission, then we will reuse that, if the action identity matches.
+ // Otherwise we'll use the initial state argument. We will emit a comment
+ // marker into the stream that indicates whether the state was reused.
+
+ let state = initialState;
+ const componentKeyPath = currentlyRenderingKeyPath;
+ const postbackFormState = getFormState(request); // $FlowIgnore[prop-missing]
+
+ const isSignatureEqual = action.$$IS_SIGNATURE_EQUAL;
+
+ if (postbackFormState !== null && typeof isSignatureEqual === 'function') {
+ const postbackKey = postbackFormState[1];
+ const postbackReferenceId = postbackFormState[2];
+ const postbackBoundArity = postbackFormState[3];
+
+ if (isSignatureEqual.call(action, postbackReferenceId, postbackBoundArity)) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+
+ if (postbackKey === nextPostbackStateKey) {
+ // This was a match
+ formStateMatchingIndex = formStateHookIndex; // Reuse the state that was submitted by the form.
+
+ state = postbackFormState[0];
+ }
+ }
+ } // Bind the state to the first argument of the action.
+
+
+ const boundAction = action.bind(null, state); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ }; // $FlowIgnore[prop-missing]
+
+
+ if (typeof boundAction.$$FORM_ACTION === 'function') {
+ // $FlowIgnore[prop-missing]
+ dispatch.$$FORM_ACTION = prefix => {
+ const metadata = boundAction.$$FORM_ACTION(prefix); // Override the action URL
+
+ if (permalink !== undefined) {
+
+ permalink += '';
+ metadata.action = permalink;
+ }
+
+ const formData = metadata.data;
+
+ if (formData) {
+ if (nextPostbackStateKey === null) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+ }
+
+ formData.append('$ACTION_KEY', nextPostbackStateKey);
+ }
+
+ return metadata;
+ };
+ }
+
+ return [state, dispatch];
+ } else {
+ // This is not a server action, so the implementation is much simpler.
+ // Bind the state to the first argument of the action.
+ const boundAction = action.bind(null, initialState); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ };
+
+ return [initialState, dispatch];
+ }
+}
+
+function useId() {
+ const task = currentlyRenderingTask;
+ const treeId = getTreeId(task.treeContext);
+ const resumableState = currentResumableState;
+
+ if (resumableState === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component.');
+ }
+
+ const localId = localIdCounter++;
+ return makeId(resumableState, treeId, localId);
+}
+
+function use(usable) {
+ if (usable !== null && typeof usable === 'object') {
+ // $FlowFixMe[method-unbinding]
+ if (typeof usable.then === 'function') {
+ // This is a thenable.
+ const thenable = usable;
+ return unwrapThenable(thenable);
+ } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = usable;
+ return readContext(context);
+ }
+ } // eslint-disable-next-line react-internal/safe-string-coercion
+
+
+ throw new Error('An unsupported type was passed to use(): ' + String(usable));
+}
+
+function unwrapThenable(thenable) {
+ const index = thenableIndexCounter;
+ thenableIndexCounter += 1;
+
+ if (thenableState === null) {
+ thenableState = createThenableState();
+ }
+
+ return trackUsedThenable(thenableState, thenable, index);
+}
+
+function unsupportedRefresh() {
+ throw new Error('Cache cannot be refreshed during server rendering.');
+}
+
+function useCacheRefresh() {
+ return unsupportedRefresh;
+}
+
+function useMemoCache(size) {
+ const data = new Array(size);
+
+ for (let i = 0; i < size; i++) {
+ data[i] = REACT_MEMO_CACHE_SENTINEL;
+ }
+
+ return data;
+}
+
+function noop$1() {}
+
+const HooksDispatcher = {
+ readContext,
+ use,
+ useContext,
+ useMemo,
+ useReducer,
+ useRef,
+ useState,
+ useInsertionEffect: noop$1,
+ useLayoutEffect: noop$1,
+ useCallback,
+ // useImperativeHandle is not run in the server environment
+ useImperativeHandle: noop$1,
+ // Effects are not run in the server environment.
+ useEffect: noop$1,
+ // Debugging effect
+ useDebugValue: noop$1,
+ useDeferredValue,
+ useTransition,
+ useId,
+ // Subscriptions are not setup in a server environment.
+ useSyncExternalStore
+};
+
+{
+ HooksDispatcher.useCacheRefresh = useCacheRefresh;
+}
+
+{
+ HooksDispatcher.useEffectEvent = useEffectEvent;
+}
+
+{
+ HooksDispatcher.useMemoCache = useMemoCache;
+}
+
+{
+ HooksDispatcher.useHostTransitionStatus = useHostTransitionStatus;
+}
+
+{
+ HooksDispatcher.useOptimistic = useOptimistic;
+ HooksDispatcher.useFormState = useFormState;
+}
+
+let currentResumableState = null;
+function setCurrentResumableState(resumableState) {
+ currentResumableState = resumableState;
+}
+
+function getCacheSignal() {
+ throw new Error('Not implemented.');
+}
+
+function getCacheForType(resourceType) {
+ throw new Error('Not implemented.');
+}
+
+const DefaultCacheDispatcher = {
+ getCacheSignal,
+ getCacheForType
+};
+
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
+const ReactCurrentCache = ReactSharedInternals.ReactCurrentCache;
+// The name might be minified but we assume that it's going to be the same generated name. Typically
+// because it's just the same compiled output in practice.
+// resume with segmentID at the index
+
+const CLIENT_RENDERED = 4; // if it errors or infinitely suspends
+
+const PENDING = 0;
+const COMPLETED = 1;
+const FLUSHED = 2;
+const ABORTED = 3;
+const ERRORED = 4;
+const POSTPONED = 5;
+const OPEN = 0;
+const CLOSING = 1;
+const CLOSED = 2; // This is a default heuristic for how to split up the HTML content into progressive
+// loading. Our goal is to be able to display additional new content about every 500ms.
+// Faster than that is unnecessary and should be throttled on the client. It also
+// adds unnecessary overhead to do more splits. We don't know if it's a higher or lower
+// end device but higher end suffer less from the overhead than lower end does from
+// not getting small enough pieces. We error on the side of low end.
+// We base this on low end 3G speeds which is about 500kbits per second. We assume
+// that there can be a reasonable drop off from max bandwidth which leaves you with
+// as little as 80%. We can receive half of that each 500ms - at best. In practice,
+// a little bandwidth is lost to processing and contention - e.g. CSS and images that
+// are downloaded along with the main content. So we estimate about half of that to be
+// the lower end throughput. In other words, we expect that you can at least show
+// about 12.5kb of content per 500ms. Not counting starting latency for the first
+// paint.
+// 500 * 1024 / 8 * .8 * 0.5 / 2
+
+const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
+
+function defaultErrorHandler(error) {
+ console['error'](error); // Don't transform to our wrapper
+
+ return null;
+}
+
+function noop() {}
+
+function createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, formState) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState,
+ renderState,
+ rootFormatContext,
+ progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: 0,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: formState === undefined ? null : formState
+ }; // This segment represents the root fallback.
+
+ const rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false); // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+function createPrerenderRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone) {
+ const request = createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, undefined); // Start tracking postponed holes during this render.
+
+ request.trackedPostpones = {
+ workingMap: new Map(),
+ rootNodes: [],
+ rootSlots: null
+ };
+ return request;
+}
+function resumeRequest(children, postponedState, renderState, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState: postponedState.resumableState,
+ renderState,
+ rootFormatContext: postponedState.rootFormatContext,
+ progressiveChunkSize: postponedState.progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: postponedState.nextSegmentId,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: null
+ };
+
+ if (typeof postponedState.replaySlots === 'number') {
+ const resumedId = postponedState.replaySlots; // We have a resume slot at the very root. This is effectively just a full rerender.
+
+ const rootSegment = createPendingSegment(request, 0, null, postponedState.rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false);
+ rootSegment.id = resumedId; // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, postponedState.rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+ }
+
+ const replay = {
+ nodes: postponedState.replayNodes,
+ slots: postponedState.replaySlots,
+ pendingTasks: 0
+ };
+ const rootTask = createReplayTask(request, null, replay, children, -1, null, abortSet, null, postponedState.rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+let currentRequest = null;
+function resolveRequest() {
+ if (currentRequest) return currentRequest;
+
+ {
+ const store = requestStorage.getStore();
+ if (store) return store;
+ }
+
+ return null;
+}
+
+function pingTask(request, task) {
+ const pingedTasks = request.pingedTasks;
+ pingedTasks.push(task);
+
+ if (request.pingedTasks.length === 1) {
+ request.flushScheduled = request.destination !== null;
+ scheduleWork(() => performWork(request));
+ }
+}
+
+function createSuspenseBoundary(request, fallbackAbortableTasks) {
+ return {
+ status: PENDING,
+ rootSegmentID: -1,
+ parentFlushed: false,
+ pendingTasks: 0,
+ completedSegments: [],
+ byteSize: 0,
+ fallbackAbortableTasks,
+ errorDigest: null,
+ resources: createBoundaryResources(),
+ trackedContentKeyPath: null,
+ trackedFallbackNode: null
+ };
+}
+
+function createRenderTask(request, thenableState, node, childIndex, blockedBoundary, blockedSegment, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ const task = {
+ replay: null,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createReplayTask(request, thenableState, replay, node, childIndex, blockedBoundary, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ replay.pendingTasks++;
+ const task = {
+ replay,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment: null,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createPendingSegment(request, index, boundary, parentFormatContext, lastPushedText, textEmbedded) {
+ return {
+ status: PENDING,
+ id: -1,
+ // lazily assigned later
+ index,
+ parentFlushed: false,
+ chunks: [],
+ children: [],
+ parentFormatContext,
+ boundary,
+ lastPushedText,
+ textEmbedded
+ };
+} // DEV-only global reference to the currently executing task
+
+function popComponentStackInDEV(task) {
+} // stash the component stack of an unwinding error until it is processed
+
+function logPostpone(request, reason) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ request.onPostpone(reason);
+}
+
+function logRecoverableError(request, error) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ const errorDigest = request.onError(error);
+
+ if (errorDigest != null && typeof errorDigest !== 'string') {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead");
+ }
+
+ return errorDigest;
+}
+
+function fatalError(request, error) {
+ // This is called outside error handling code such as if the root errors outside
+ // a suspense boundary or if the root suspense boundary's fallback errors.
+ // It's also called if React itself or its host configs errors.
+ const onShellError = request.onShellError;
+ onShellError(error);
+ const onFatalError = request.onFatalError;
+ onFatalError(error);
+
+ if (request.destination !== null) {
+ request.status = CLOSED;
+ closeWithError(request.destination, error);
+ } else {
+ request.status = CLOSING;
+ request.fatalError = error;
+ }
+}
+
+function renderSuspenseBoundary(request, someTask, keyPath, props) {
+ if (someTask.replay !== null) {
+ // If we're replaying through this pass, it means we're replaying through
+ // an already completed Suspense boundary. It's too late to do anything about it
+ // so we can just render through it.
+ const prevKeyPath = someTask.keyPath;
+ someTask.keyPath = keyPath;
+ const content = props.children;
+
+ try {
+ renderNode(request, someTask, content, -1);
+ } finally {
+ someTask.keyPath = prevKeyPath;
+ }
+
+ return;
+ } // $FlowFixMe: Refined.
+
+
+ const task = someTask;
+ const prevKeyPath = task.keyPath;
+ const parentBoundary = task.blockedBoundary;
+ const parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for
+ // the fallback so that we can later replace that segment with the content.
+ // This also lets us split out the main content even if it doesn't suspend,
+ // in case it ends up generating a large subtree of content.
+
+ const fallback = props.fallback;
+ const content = props.children;
+ const fallbackAbortSet = new Set();
+ const newBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+
+ if (request.trackedPostpones !== null) {
+ newBoundary.trackedContentKeyPath = keyPath;
+ }
+
+ const insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback.
+
+ const boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false);
+ parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent
+
+ parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately.
+
+ const contentRootSegment = createPendingSegment(request, 0, null, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is
+ // no parent segment so there's nothing to wait on.
+
+ contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks.
+ // I suspect that there might be some efficiency benefits from not creating the suspended task
+ // and instead just using the stack if possible.
+ // TODO: Call this directly instead of messing with saving and restoring contexts.
+ // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and which segment
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = newBoundary;
+ task.blockedSegment = contentRootSegment;
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, newBoundary.resources);
+ }
+
+ task.keyPath = keyPath;
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+ pushSegmentFinale(contentRootSegment.chunks, request.renderState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded);
+ contentRootSegment.status = COMPLETED;
+ queueCompletedSegment(newBoundary, contentRootSegment);
+
+ if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
+ newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ contentRootSegment.status = ERRORED;
+ newBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ newBoundary.errorDigest = errorDigest;
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.blockedSegment = parentSegment;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]];
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones !== null) {
+ // We create a detached replay node to track any postpones inside the fallback.
+ const fallbackReplayNode = [fallbackKeyPath[1], fallbackKeyPath[2], [], null];
+ trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
+
+ if (newBoundary.status === POSTPONED) {
+ // This must exist now.
+ const boundaryReplayNode = trackedPostpones.workingMap.get(keyPath);
+ boundaryReplayNode[4] = fallbackReplayNode;
+ } else {
+ // We might not inject it into the postponed tree, unless the content actually
+ // postpones too. We need to keep track of it until that happpens.
+ newBoundary.trackedFallbackNode = fallbackReplayNode;
+ }
+ } // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+
+ const suspendedFallbackTask = createRenderTask(request, null, fallback, -1, parentBoundary, boundarySegment, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function replaySuspenseBoundary(request, task, keyPath, props, id, childNodes, childSlots, fallbackNodes, fallbackSlots) {
+ const prevKeyPath = task.keyPath;
+ const previousReplaySet = task.replay;
+ const parentBoundary = task.blockedBoundary;
+ const content = props.children;
+ const fallback = props.fallback;
+ const fallbackAbortSet = new Set();
+ const resumedBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = id; // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and replay node
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = resumedBoundary;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, resumedBoundary.resources);
+ }
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+
+ if (resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING) {
+ resumedBoundary.status = COMPLETED;
+ request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ resumedBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ resumedBoundary.errorDigest = errorDigest;
+
+ task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted.
+
+ request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task.
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.replay = previousReplaySet;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+ const fallbackReplay = {
+ nodes: fallbackNodes,
+ slots: fallbackSlots,
+ pendingTasks: 0
+ };
+ const suspendedFallbackTask = createReplayTask(request, null, fallbackReplay, fallback, -1, parentBoundary, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function renderHostElement(request, task, keyPath, type, props) {
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ const children = props.children; // TODO: Make this a Config for replaying.
+
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ } else {
+ // Render
+ const children = pushStartInstance(segment.chunks, type, props, request.resumableState, request.renderState, task.formatContext, segment.lastPushedText);
+ segment.lastPushedText = false;
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ pushEndInstance(segment.chunks, type, props, request.resumableState, prevContext);
+ segment.lastPushedText = false;
+ }
+}
+
+function shouldConstruct(Component) {
+ return Component.prototype && Component.prototype.isReactComponent;
+}
+
+function renderWithHooks(request, task, keyPath, prevThenableState, Component, props, secondArg) {
+ const componentIdentity = {};
+ prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState);
+ const result = Component(props, secondArg);
+ return finishHooks(Component, props, result, secondArg);
+}
+
+function finishClassComponent(request, task, keyPath, instance, Component, props) {
+ const nextChildren = instance.render();
+
+ {
+ const childContextTypes = Component.childContextTypes;
+
+ if (childContextTypes !== null && childContextTypes !== undefined) {
+ const previousContext = task.legacyContext;
+ const mergedContext = processChildContext(instance, Component, previousContext, childContextTypes);
+ task.legacyContext = mergedContext;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.legacyContext = previousContext;
+ return;
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderClassComponent(request, task, keyPath, Component, props) {
+ const maskedContext = getMaskedContext(Component, task.legacyContext) ;
+ const instance = constructClassInstance(Component, props, maskedContext);
+ mountClassInstance(instance, Component, props, maskedContext);
+ finishClassComponent(request, task, keyPath, instance, Component);
+}
+// components for some reason.
+
+function renderIndeterminateComponent(request, task, keyPath, prevThenableState, Component, props) {
+ let legacyContext;
+
+ {
+ legacyContext = getMaskedContext(Component, task.legacyContext);
+ }
+
+ const value = renderWithHooks(request, task, keyPath, prevThenableState, Component, props, legacyContext);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+
+ if ( // Run these checks in production only if the flag is off.
+ // Eventually we'll delete this branch altogether.
+ typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
+
+ mountClassInstance(value, Component, props, legacyContext);
+ finishClassComponent(request, task, keyPath, value, Component);
+ } else {
+
+ finishFunctionComponent(request, task, keyPath, value, hasId, formStateCount, formStateMatchingIndex);
+ }
+}
+
+function finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex) {
+ let didEmitFormStateMarkers = false;
+
+ if (formStateCount !== 0 && request.formState !== null) {
+ // For each useFormState hook, emit a marker that indicates whether we
+ // rendered using the form state passed at the root. We only emit these
+ // markers if form state is passed at the root.
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ didEmitFormStateMarkers = true;
+ const target = segment.chunks;
+
+ for (let i = 0; i < formStateCount; i++) {
+ if (i === formStateMatchingIndex) {
+ pushFormStateMarkerIsMatching(target);
+ } else {
+ pushFormStateMarkerIsNotMatching(target);
+ }
+ }
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+
+ if (hasId) {
+ // This component materialized an id. We treat this as its own level, with
+ // a single "child" slot.
+ const prevTreeContext = task.treeContext;
+ const totalChildren = 1;
+ const index = 0; // Modify the id context. Because we'll need to reset this if something
+ // suspends or errors, we'll use the non-destructive render path.
+
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
+ renderNode(request, task, children, -1); // Like the other contexts, this does not need to be in a finally block
+ // because renderNode takes care of unwinding the stack.
+
+ task.treeContext = prevTreeContext;
+ } else if (didEmitFormStateMarkers) {
+ // If there were formState hooks, we must use the non-destructive path
+ // because this component is not a pure indirection; we emitted markers
+ // to the stream.
+ renderNode(request, task, children, -1);
+ } else {
+ // We're now successfully past this task, and we haven't modified the
+ // context stack. We don't have to pop back to the previous task every
+ // again, so we can use the destructive recursive form.
+ renderNodeDestructive(request, task, null, children, -1);
+ }
+
+ task.keyPath = prevKeyPath;
+}
+
+function resolveDefaultProps(Component, baseProps) {
+ if (Component && Component.defaultProps) {
+ // Resolve default props. Taken from ReactElement
+ const props = assign({}, baseProps);
+ const defaultProps = Component.defaultProps;
+
+ for (const propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+
+ return props;
+ }
+
+ return baseProps;
+}
+
+function renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref) {
+ const children = renderWithHooks(request, task, keyPath, prevThenableState, type.render, props, ref);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+ finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex);
+}
+
+function renderMemo(request, task, keyPath, prevThenableState, type, props, ref) {
+ const innerType = type.type;
+ const resolvedProps = resolveDefaultProps(innerType, props);
+ renderElement(request, task, keyPath, prevThenableState, innerType, resolvedProps, ref);
+}
+
+function renderContextConsumer(request, task, keyPath, context, props) {
+
+ const render = props.children;
+
+ const newValue = readContext$1(context);
+ const newChildren = render(newValue);
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, newChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderContextProvider(request, task, keyPath, type, props) {
+ const context = type._context;
+ const value = props.value;
+ const children = props.children;
+
+ const prevKeyPath = task.keyPath;
+ task.context = pushProvider(context, value);
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, children, -1);
+ task.context = popProvider();
+ task.keyPath = prevKeyPath;
+}
+
+function renderLazyComponent(request, task, keyPath, prevThenableState, lazyComponent, props, ref) {
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+ const Component = init(payload);
+ const resolvedProps = resolveDefaultProps(Component, props);
+ renderElement(request, task, keyPath, prevThenableState, Component, resolvedProps, ref);
+}
+
+function renderOffscreen(request, task, keyPath, props) {
+ const mode = props.mode;
+
+ if (mode === 'hidden') ; else {
+ // A visible Offscreen boundary is treated exactly like a fragment: a
+ // pure indirection.
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ }
+}
+
+function renderElement(request, task, keyPath, prevThenableState, type, props, ref) {
+ if (typeof type === 'function') {
+ if (shouldConstruct(type)) {
+ renderClassComponent(request, task, keyPath, type, props);
+ return;
+ } else {
+ renderIndeterminateComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+
+ if (typeof type === 'string') {
+ renderHostElement(request, task, keyPath, type, props);
+ return;
+ }
+
+ switch (type) {
+ // LegacyHidden acts the same as a fragment. This only works because we
+ // currently assume that every instance of LegacyHidden is accompanied by a
+ // host component wrapper. In the hidden mode, the host component is given a
+ // `hidden` attribute, which ensures that the initial HTML is not visible.
+ // To support the use of LegacyHidden as a true fragment, without an extra
+ // DOM node, we would have to hide the initial HTML in some other way.
+ // TODO: Delete in LegacyHidden. It's an unstable API only used in the
+ // www build. As a migration step, we could add a special prop to Offscreen
+ // that simulates the old behavior (no hiding, no change to effects).
+ case REACT_LEGACY_HIDDEN_TYPE:
+ case REACT_DEBUG_TRACING_MODE_TYPE:
+ case REACT_STRICT_MODE_TYPE:
+ case REACT_PROFILER_TYPE:
+ case REACT_FRAGMENT_TYPE:
+ {
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_OFFSCREEN_TYPE:
+ {
+ renderOffscreen(request, task, keyPath, props);
+ return;
+ }
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ {
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_SCOPE_TYPE:
+ {
+
+ throw new Error('ReactDOMServer does not yet support scope components.');
+ }
+
+ case REACT_SUSPENSE_TYPE:
+ {
+ {
+ renderSuspenseBoundary(request, task, keyPath, props);
+ }
+
+ return;
+ }
+ }
+
+ if (typeof type === 'object' && type !== null) {
+ switch (type.$$typeof) {
+ case REACT_FORWARD_REF_TYPE:
+ {
+ renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_MEMO_TYPE:
+ {
+ renderMemo(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_PROVIDER_TYPE:
+ {
+ renderContextProvider(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_CONTEXT_TYPE:
+ {
+ renderContextConsumer(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_LAZY_TYPE:
+ {
+ renderLazyComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+ }
+
+ let info = '';
+
+ throw new Error('Element type is invalid: expected a string (for built-in ' + 'components) or a class/function (for composite components) ' + ("but got: " + (type == null ? type : typeof type) + "." + info));
+}
+
+function resumeNode(request, task, segmentId, node, childIndex) {
+ const prevReplay = task.replay;
+ const blockedBoundary = task.blockedBoundary;
+ const resumedSegment = createPendingSegment(request, 0, null, task.formatContext, false, false);
+ resumedSegment.id = segmentId;
+ resumedSegment.parentFlushed = true;
+
+ try {
+ // Convert the current ReplayTask to a RenderTask.
+ const renderTask = task;
+ renderTask.replay = null;
+ renderTask.blockedSegment = resumedSegment;
+ renderNode(request, task, node, childIndex);
+ resumedSegment.status = COMPLETED;
+
+ if (blockedBoundary === null) {
+ request.completedRootSegment = resumedSegment;
+ } else {
+ queueCompletedSegment(blockedBoundary, resumedSegment);
+
+ if (blockedBoundary.parentFlushed) {
+ request.partialBoundaries.push(blockedBoundary);
+ }
+ }
+ } finally {
+ // Restore to a ReplayTask.
+ task.replay = prevReplay;
+ task.blockedSegment = null;
+ }
+}
+
+function replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, replay) {
+ // We're replaying. Find the path to follow.
+ const replayNodes = replay.nodes;
+
+ for (let i = 0; i < replayNodes.length; i++) {
+ // Flow doesn't support refinement on tuples so we do it manually here.
+ const node = replayNodes[i];
+
+ if (keyOrIndex !== node[1]) {
+ continue;
+ }
+
+ if (node.length === 4) {
+ // Matched a replayable path.
+ // Let's double check that the component name matches as a precaution.
+ if (name !== null && name !== node[0]) {
+ throw new Error('Expected the resume to render <' + node[0] + '> in this slot but instead it rendered <' + name + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ const currentNode = task.node;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0 // TODO check remaining slots
+ ) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ if (task.node === currentNode) {
+ // This same element suspended so we need to pop the replay we just added.
+ task.replay = replay;
+ }
+
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay;
+ } else {
+ // Let's double check that the component type matches.
+ if (type !== REACT_SUSPENSE_TYPE) {
+ const expectedType = 'Suspense';
+ throw new Error('Expected the resume to render <' + expectedType + '> in this slot but instead it rendered <' + (getComponentNameFromType(type) || 'Unknown') + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ } // Matched a replayable path.
+
+
+ replaySuspenseBoundary(request, task, keyPath, props, node[5], node[2], node[3], node[4] === null ? [] : node[4][2], node[4] === null ? null : node[4][3]);
+ } // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+
+ replayNodes.splice(i, 1);
+ return;
+ } // We didn't find any matching nodes. We assume that this element was already
+ // rendered in the prelude and skip it.
+
+} // $FlowFixMe[missing-local-annot]
+
+function renderNodeDestructive(request, task, // The thenable state reused from the previous attempt, if any. This is almost
+// always null, except when called by retryTask.
+prevThenableState, node, childIndex) {
+ {
+ return renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex);
+ }
+} // This function by it self renders a node and consumes the task by mutating it
+// to update the current execution state.
+
+
+function renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex) {
+ if (task.replay !== null && typeof task.replay.slots === 'number') {
+ // TODO: Figure out a cheaper place than this hot path to do this check.
+ const resumeSegmentID = task.replay.slots;
+ resumeNode(request, task, resumeSegmentID, node, childIndex);
+ return;
+ } // Stash the node we're working on. We'll pick up from this task in case
+ // something suspends.
+
+
+ task.node = node;
+ task.childIndex = childIndex; // Handle object types
+
+ if (typeof node === 'object' && node !== null) {
+ switch (node.$$typeof) {
+ case REACT_ELEMENT_TYPE:
+ {
+ const element = node;
+ const type = element.type;
+ const key = element.key;
+ const props = element.props;
+ const ref = element.ref;
+ const name = getComponentNameFromType(type);
+ const keyOrIndex = key == null ? childIndex === -1 ? 0 : childIndex : key;
+ const keyPath = [task.keyPath, name, keyOrIndex];
+
+ if (task.replay !== null) {
+ replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, task.replay); // No matches found for this node. We assume it's already emitted in the
+ // prelude and skip it during the replay.
+ } else {
+ // We're doing a plain render.
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+ }
+
+ return;
+ }
+
+ case REACT_PORTAL_TYPE:
+ throw new Error('Portals are not currently supported by the server renderer. ' + 'Render them conditionally so that they only appear on the client render.');
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyNode = node;
+ const payload = lazyNode._payload;
+ const init = lazyNode._init;
+ let resolvedNode;
+
+ {
+ resolvedNode = init(payload);
+ }
+
+ renderNodeDestructive(request, task, null, resolvedNode, childIndex);
+ return;
+ }
+ }
+
+ if (isArray(node)) {
+ renderChildrenArray(request, task, node, childIndex);
+ return;
+ }
+
+ const iteratorFn = getIteratorFn(node);
+
+ if (iteratorFn) {
+
+ const iterator = iteratorFn.call(node);
+
+ if (iterator) {
+ // We need to know how many total children are in this set, so that we
+ // can allocate enough id slots to acommodate them. So we must exhaust
+ // the iterator before we start recursively rendering the children.
+ // TODO: This is not great but I think it's inherent to the id
+ // generation algorithm.
+ let step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that.
+
+ if (!step.done) {
+ const children = [];
+
+ do {
+ children.push(step.value);
+ step = iterator.next();
+ } while (!step.done);
+
+ renderChildrenArray(request, task, children, childIndex);
+ return;
+ }
+
+ return;
+ }
+ } // Usables are a valid React node type. When React encounters a Usable in
+ // a child position, it unwraps it using the same algorithm as `use`. For
+ // example, for promises, React will throw an exception to unwind the
+ // stack, then replay the component once the promise resolves.
+ //
+ // A difference from `use` is that React will keep unwrapping the value
+ // until it reaches a non-Usable type.
+ //
+ // e.g. Usable>> should resolve to T
+
+
+ const maybeUsable = node;
+
+ if (typeof maybeUsable.then === 'function') {
+ const thenable = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable), childIndex);
+ }
+
+ if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, readContext$1(context), childIndex);
+ } // $FlowFixMe[method-unbinding]
+
+
+ const childString = Object.prototype.toString.call(node);
+ throw new Error("Objects are not valid as a React child (found: " + (childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString) + "). " + 'If you meant to render a collection of children, use an array ' + 'instead.');
+ }
+
+ if (typeof node === 'string') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+
+ if (typeof node === 'number') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, '' + node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+}
+
+function replayFragment(request, task, children, childIndex) {
+ // If we're supposed follow this array, we'd expect to see a ReplayNode matching
+ // this fragment.
+ const replay = task.replay;
+ const replayNodes = replay.nodes;
+
+ for (let j = 0; j < replayNodes.length; j++) {
+ const node = replayNodes[j];
+
+ if (node[1] !== childIndex) {
+ continue;
+ } // Matched a replayable path.
+
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderChildrenArray(request, task, children, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+ // This is an error, stash the component stack if it is null.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay; // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ replayNodes.splice(j, 1);
+ break;
+ }
+}
+
+function renderChildrenArray(request, task, children, childIndex) {
+ const prevKeyPath = task.keyPath;
+
+ if (childIndex !== -1) {
+ task.keyPath = [task.keyPath, 'Fragment', childIndex];
+
+ if (task.replay !== null) {
+ replayFragment(request, // $FlowFixMe: Refined.
+ task, children, childIndex);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ const prevTreeContext = task.treeContext;
+ const totalChildren = children.length;
+
+ if (task.replay !== null) {
+ // Replay
+ // First we need to check if we have any resume slots at this level.
+ const resumeSlots = task.replay.slots;
+
+ if (resumeSlots !== null && typeof resumeSlots === 'object') {
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ const resumeSegmentID = resumeSlots[i]; // TODO: If this errors we should still continue with the next sibling.
+
+ if (typeof resumeSegmentID === 'number') {
+ resumeNode(request, task, resumeSegmentID, node, i); // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ delete resumeSlots[i];
+ } else {
+ renderNode(request, task, node, i);
+ }
+ }
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ renderNode(request, task, node, i);
+ } // Because this context is always set right before rendering every child, we
+ // only need to reset it to the previous value at the very end.
+
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+}
+
+function trackPostpone(request, trackedPostpones, task, segment) {
+ segment.status = POSTPONED;
+ const keyPath = task.keyPath;
+ const boundary = task.blockedBoundary;
+
+ if (boundary === null) {
+ segment.id = request.nextSegmentId++;
+ trackedPostpones.rootSlots = segment.id;
+
+ if (request.completedRootSegment !== null) {
+ // Postpone the root if this was a deeper segment.
+ request.completedRootSegment.status = POSTPONED;
+ }
+
+ return;
+ }
+
+ if (boundary !== null && boundary.status === PENDING) {
+ boundary.status = POSTPONED; // We need to eagerly assign it an ID because we'll need to refer to
+ // it before flushing and we know that we can't inline it.
+
+ boundary.rootSegmentID = request.nextSegmentId++;
+ const boundaryKeyPath = boundary.trackedContentKeyPath;
+
+ if (boundaryKeyPath === null) {
+ throw new Error('It should not be possible to postpone at the root. This is a bug in React.');
+ }
+
+ const fallbackReplayNode = boundary.trackedFallbackNode;
+ const children = [];
+
+ if (boundaryKeyPath === keyPath && task.childIndex === -1) {
+ // Since we postponed directly in the Suspense boundary we can't have written anything
+ // to its segment. Therefore this will end up becoming the root segment.
+ segment.id = boundary.rootSegmentID; // We postponed directly inside the Suspense boundary so we mark this for resuming.
+
+ const boundaryNode = [boundaryKeyPath[1], boundaryKeyPath[2], children, boundary.rootSegmentID, fallbackReplayNode, boundary.rootSegmentID];
+ trackedPostpones.workingMap.set(boundaryKeyPath, boundaryNode);
+ addToReplayParent(boundaryNode, boundaryKeyPath[0], trackedPostpones);
+ return;
+ } else {
+ let boundaryNode = trackedPostpones.workingMap.get(boundaryKeyPath);
+
+ if (boundaryNode === undefined) {
+ boundaryNode = [boundaryKeyPath[1], boundaryKeyPath[2], children, null, fallbackReplayNode, boundary.rootSegmentID];
+ trackedPostpones.workingMap.set(boundaryKeyPath, boundaryNode);
+ addToReplayParent(boundaryNode, boundaryKeyPath[0], trackedPostpones);
+ } else {
+ // Upgrade to ReplaySuspenseBoundary.
+ const suspenseBoundary = boundaryNode;
+ suspenseBoundary[4] = fallbackReplayNode;
+ suspenseBoundary[5] = boundary.rootSegmentID;
+ } // Fall through to add the child node.
+
+ }
+ } // We know that this will leave a hole so we might as well assign an ID now.
+ // We might have one already if we had a parent that gave us its ID.
+
+
+ if (segment.id === -1) {
+ if (segment.parentFlushed && boundary !== null) {
+ // If this segment's parent was already flushed, it means we really just
+ // skipped the parent and this segment is now the root.
+ segment.id = boundary.rootSegmentID;
+ } else {
+ segment.id = request.nextSegmentId++;
+ }
+ }
+
+ if (task.childIndex === -1) {
+ // Resume starting from directly inside the previous parent element.
+ if (keyPath === null) {
+ trackedPostpones.rootSlots = segment.id;
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let resumableNode = workingMap.get(keyPath);
+
+ if (resumableNode === undefined) {
+ resumableNode = [keyPath[1], keyPath[2], [], segment.id];
+ addToReplayParent(resumableNode, keyPath[0], trackedPostpones);
+ } else {
+ resumableNode[3] = segment.id;
+ }
+ }
+ } else {
+ let slots;
+
+ if (keyPath === null) {
+ slots = trackedPostpones.rootSlots;
+
+ if (slots === null) {
+ slots = trackedPostpones.rootSlots = {};
+ } else if (typeof slots === 'number') {
+ throw new Error('It should not be possible to postpone both at the root of an element ' + 'as well as a slot below. This is a bug in React.');
+ }
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let resumableNode = workingMap.get(keyPath);
+
+ if (resumableNode === undefined) {
+ slots = {};
+ resumableNode = [keyPath[1], keyPath[2], [], slots];
+ workingMap.set(keyPath, resumableNode);
+ addToReplayParent(resumableNode, keyPath[0], trackedPostpones);
+ } else {
+ slots = resumableNode[3];
+
+ if (slots === null) {
+ slots = resumableNode[3] = {};
+ } else if (typeof slots === 'number') {
+ throw new Error('It should not be possible to postpone both at the root of an element ' + 'as well as a slot below. This is a bug in React.');
+ }
+ }
+ }
+
+ slots[task.childIndex] = segment.id;
+ }
+}
+
+function injectPostponedHole(request, task, reason) {
+ logPostpone(request, reason); // Something suspended, we'll need to create a new segment and resolve it later.
+
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ return newSegment;
+}
+
+function spawnNewSuspendedReplayTask(request, task, thenableState, x) {
+ const newTask = createReplayTask(request, thenableState, task.replay, task.node, task.childIndex, task.blockedBoundary, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+}
+
+function spawnNewSuspendedRenderTask(request, task, thenableState, x) {
+ // Something suspended, we'll need to create a new segment and resolve it later.
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ const newTask = createRenderTask(request, thenableState, task.node, task.childIndex, task.blockedBoundary, newSegment, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+} // This is a non-destructive form of rendering a node. If it suspends it spawns
+// a new task and restores the context of this task to what it was before.
+
+
+function renderNode(request, task, node, childIndex) {
+ // Snapshot the current context in case something throws to interrupt the
+ // process.
+ const previousFormatContext = task.formatContext;
+ const previousLegacyContext = task.legacyContext;
+ const previousContext = task.context;
+ const previousKeyPath = task.keyPath;
+ const previousTreeContext = task.treeContext;
+
+ let x; // Store how much we've pushed at this point so we can reset it in case something
+ // suspended partially through writing something.
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState();
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedReplayTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode.
+
+ }
+ } else {
+ // Render
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedRenderTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+
+ if (request.trackedPostpones !== null && x.$$typeof === REACT_POSTPONE_TYPE && task.blockedBoundary !== null // bubble if we're postponing in the shell
+ ) {
+ // If we're tracking postpones, we inject a hole here and continue rendering
+ // sibling. Similar to suspending. If we're not tracking, we treat it more like
+ // an error. Notably this doesn't spawn a new task since nothing will fill it
+ // in during this prerender.
+ const postponeInstance = x;
+ const trackedPostpones = request.trackedPostpones;
+ const postponedSegment = injectPostponedHole(request, task, // We don't use ReplayTasks in prerenders.
+ postponeInstance.message);
+ trackPostpone(request, trackedPostpones, task, postponedSegment); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ return;
+ }
+ }
+ }
+ } // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ // Let's terminate the rest of the tree and don't render any siblings.
+
+
+ throw x;
+}
+
+function erroredReplay(request, boundary, error, replayNodes, resumeSlots) {
+ // Erroring during a replay doesn't actually cause an error by itself because
+ // that component has already rendered. What causes the error is the resumable
+ // points that we did not yet finish which will be below the point of the reset.
+ // For example, if we're replaying a path to a Suspense boundary that is not done
+ // that doesn't error the parent Suspense boundary.
+ // This might be a bit strange that the error in a parent gets thrown at a child.
+ // We log it only once and reuse the digest.
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ abortRemainingReplayNodes(request, boundary, replayNodes, resumeSlots, error, errorDigest);
+}
+
+function erroredTask(request, boundary, error) {
+ // Report the error to a global handler.
+ let errorDigest;
+
+ if (typeof error === 'object' && error !== null && error.$$typeof === REACT_POSTPONE_TYPE) {
+ const postponeInstance = error;
+ logPostpone(request, postponeInstance.message); // TODO: Figure out a better signal than a magic digest value.
+
+ errorDigest = 'POSTPONE';
+ } else {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ if (boundary === null) {
+ fatalError(request, error);
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+ // so we can flush it, if the parent already flushed.
+
+
+ if (boundary.parentFlushed) {
+ // We don't have a preference where in the queue this goes since it's likely
+ // to error on the client anyway. However, intentionally client-rendered
+ // boundaries should be flushed earlier so that they can start on the client.
+ // We reuse the same queue for errors.
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function abortTaskSoft(task) {
+ // This aborts task without aborting the parent boundary that it blocks.
+ // It's used for when we didn't need this task to complete the tree.
+ // If task was needed, then it should use abortTask instead.
+ const request = this;
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ finishedTask(request, boundary, segment);
+ }
+}
+
+function abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest) {
+ const resumedBoundary = createSuspenseBoundary(request, new Set());
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = rootSegmentID;
+ resumedBoundary.status = CLIENT_RENDERED;
+ resumedBoundary.errorDigest = errorDigest;
+
+ if (resumedBoundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(resumedBoundary);
+ }
+}
+
+function abortRemainingReplayNodes(request, boundary, nodes, slots, error, errorDigest) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+
+ if (node.length === 4) {
+ abortRemainingReplayNodes(request, boundary, node[2], node[3], error, errorDigest);
+ } else {
+ const boundaryNode = node;
+ const rootSegmentID = boundaryNode[5];
+ abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest);
+ }
+ } // Empty the set, since we've cleared it now.
+
+
+ nodes.length = 0;
+
+ if (slots !== null) {
+ // We had something still to resume in the parent boundary. We must trigger
+ // the error on the parent boundary since it's not able to complete.
+ if (boundary === null) {
+ throw new Error('We should not have any resumable nodes in the shell. ' + 'This is a bug in React.');
+ } else if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // Empty the set
+
+
+ if (typeof slots === 'object') {
+ for (const index in slots) {
+ delete slots[index];
+ }
+ }
+ }
+}
+
+function abortTask(task, request, error) {
+ // This aborts the task and aborts the parent that it blocks, putting it into
+ // client rendered mode.
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ }
+
+ if (boundary === null) {
+ if (request.status !== CLOSING && request.status !== CLOSED) {
+ const replay = task.replay;
+
+ if (replay === null) {
+ // We didn't complete the root so we have nothing to show. We can close
+ // the request;
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ return;
+ } else {
+ // If the shell aborts during a replay, that's not a fatal error. Instead
+ // we should be able to recover by client rendering all the root boundaries in
+ // the ReplaySet.
+ replay.pendingTasks--;
+
+ if (replay.pendingTasks === 0 && replay.nodes.length > 0) {
+ const errorDigest = logRecoverableError(request, error);
+ abortRemainingReplayNodes(request, null, replay.nodes, replay.slots, error, errorDigest);
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ }
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = logRecoverableError(request, error);
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // If this boundary was still pending then we haven't already cancelled its fallbacks.
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
+
+
+ boundary.fallbackAbortableTasks.forEach(fallbackTask => abortTask(fallbackTask, request, error));
+ boundary.fallbackAbortableTasks.clear();
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeShell(request) {
+ if (request.trackedPostpones === null) {
+ // We only emit early preloads on shell completion for renders. For prerenders
+ // we wait for the entire Request to finish because we are not responding to a
+ // live request and can wait for as much data as possible.
+ // we should only be calling completeShell when the shell is complete so we
+ // just use a literal here
+ const shellComplete = true;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ } // We have completed the shell so the shell can't error anymore.
+
+
+ request.onShellError = noop;
+ const onShellReady = request.onShellReady;
+ onShellReady();
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeAll(request) {
+ // During a render the shell must be complete if the entire request is finished
+ // however during a Prerender it is possible that the shell is incomplete because
+ // it postponed. We cannot use rootPendingTasks in the prerender case because
+ // those hit zero even when the shell postpones. Instead we look at the completedRootSegment
+ const shellComplete = request.trackedPostpones === null ? // Render, we assume it is completed
+ true : // Prerender Request, we use the state of the root segment
+ request.completedRootSegment === null || request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ const onAllReady = request.onAllReady;
+ onAllReady();
+}
+
+function queueCompletedSegment(boundary, segment) {
+ if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) {
+ // This is an empty segment. There's nothing to write, so we can instead transfer the ID
+ // to the child. That way any existing references point to the child.
+ const childSegment = segment.children[0];
+ childSegment.id = segment.id;
+ childSegment.parentFlushed = true;
+
+ if (childSegment.status === COMPLETED) {
+ queueCompletedSegment(boundary, childSegment);
+ }
+ } else {
+ const completedSegments = boundary.completedSegments;
+ completedSegments.push(segment);
+ }
+}
+
+function finishedTask(request, boundary, segment) {
+ if (boundary === null) {
+ if (segment !== null && segment.parentFlushed) {
+ if (request.completedRootSegment !== null) {
+ throw new Error('There can only be one root segment. This is a bug in React.');
+ }
+
+ request.completedRootSegment = segment;
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status === CLIENT_RENDERED) ; else if (boundary.pendingTasks === 0) {
+ if (boundary.status === PENDING) {
+ boundary.status = COMPLETED;
+ } // This must have been the last segment we were waiting on. This boundary is now complete.
+
+
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent segment already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ }
+ }
+
+ if (boundary.parentFlushed) {
+ // The segment might be part of a segment that didn't flush yet, but if the boundary's
+ // parent flushed, we need to schedule the boundary to be emitted.
+ request.completedBoundaries.push(boundary);
+ } // We can now cancel any pending task on the fallback since we won't need to show it anymore.
+ // This needs to happen after we read the parentFlushed flags because aborting can finish
+ // work which can trigger user code, which can start flushing, which can change those flags.
+ // If the boundary was POSTPONED, we still need to finish the fallback first.
+
+
+ if (boundary.status === COMPLETED) {
+ boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
+ boundary.fallbackAbortableTasks.clear();
+ }
+ } else {
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length === 1) {
+ // This is the first time since we last flushed that we completed anything.
+ // We can schedule this boundary to emit its partially completed segments early
+ // in case the parent has already been flushed.
+ if (boundary.parentFlushed) {
+ request.partialBoundaries.push(boundary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function retryTask(request, task) {
+ {
+ const blockedBoundary = task.blockedBoundary;
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, blockedBoundary ? blockedBoundary.resources : null);
+ }
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ retryReplayTask(request, // $FlowFixMe: Refined.
+ task);
+ } else {
+ retryRenderTask(request, // $FlowFixMe: Refined.
+ task, segment);
+ }
+}
+
+function retryRenderTask(request, task, segment) {
+ if (segment.status !== PENDING) {
+ // We completed this by other means before we had a chance to retry it.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+ pushSegmentFinale(segment.chunks, request.renderState, segment.lastPushedText, segment.textEmbedded);
+ task.abortSet.delete(task);
+ segment.status = COMPLETED;
+ finishedTask(request, task.blockedBoundary, segment);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ } else if (request.trackedPostpones !== null && x.$$typeof === REACT_POSTPONE_TYPE) {
+ // If we're tracking postpones, we mark this segment as postponed and finish
+ // the task without filling it in. If we're not tracking, we treat it more like
+ // an error.
+ const trackedPostpones = request.trackedPostpones;
+ task.abortSet.delete(task);
+ const postponeInstance = x;
+ logPostpone(request, postponeInstance.message);
+ trackPostpone(request, trackedPostpones, task, segment);
+ finishedTask(request, task.blockedBoundary, segment);
+ return;
+ }
+ }
+
+ task.abortSet.delete(task);
+ segment.status = ERRORED;
+ erroredTask(request, task.blockedBoundary, x);
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function retryReplayTask(request, task) {
+ if (task.replay.pendingTasks === 0) {
+ // There are no pending tasks working on this set, so we must have aborted.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ finishedTask(request, task.blockedBoundary, null);
+ } catch (thrownValue) {
+ resetHooksState();
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ erroredReplay(request, task.blockedBoundary, x, task.replay.nodes, task.replay.slots);
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function performWork(request) {
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ const prevContext = getActiveContext();
+ const prevDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = HooksDispatcher;
+ let prevCacheDispatcher;
+
+ {
+ prevCacheDispatcher = ReactCurrentCache.current;
+ ReactCurrentCache.current = DefaultCacheDispatcher;
+ }
+
+ const prevRequest = currentRequest;
+ currentRequest = request;
+
+ const prevResumableState = currentResumableState;
+ setCurrentResumableState(request.resumableState);
+
+ try {
+ const pingedTasks = request.pingedTasks;
+ let i;
+
+ for (i = 0; i < pingedTasks.length; i++) {
+ const task = pingedTasks[i];
+ retryTask(request, task);
+ }
+
+ pingedTasks.splice(0, i);
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ } finally {
+ setCurrentResumableState(prevResumableState);
+ ReactCurrentDispatcher.current = prevDispatcher;
+
+ {
+ ReactCurrentCache.current = prevCacheDispatcher;
+ }
+
+ if (prevDispatcher === HooksDispatcher) {
+ // This means that we were in a reentrant work loop. This could happen
+ // in a renderer that supports synchronous work like renderToString,
+ // when it's called from within another renderer.
+ // Normally we don't bother switching the contexts to their root/default
+ // values when leaving because we'll likely need the same or similar
+ // context again. However, when we're inside a synchronous loop like this
+ // we'll to restore the context to what it was before returning.
+ switchContext(prevContext);
+ }
+
+ currentRequest = prevRequest;
+ }
+}
+
+function flushSubtree(request, destination, segment) {
+ segment.parentFlushed = true;
+
+ switch (segment.status) {
+ case PENDING:
+ {
+ // We're emitting a placeholder for this segment to be filled in later.
+ // Therefore we'll need to assign it an ID - to refer to it by.
+ segment.id = request.nextSegmentId++; // Fallthrough
+ }
+
+ case POSTPONED:
+ {
+ const segmentID = segment.id; // When this segment finally completes it won't be embedded in text since it will flush separately
+
+ segment.lastPushedText = false;
+ segment.textEmbedded = false;
+ return writePlaceholder(destination, request.renderState, segmentID);
+ }
+
+ case COMPLETED:
+ {
+ segment.status = FLUSHED;
+ let r = true;
+ const chunks = segment.chunks;
+ let chunkIdx = 0;
+ const children = segment.children;
+
+ for (let childIdx = 0; childIdx < children.length; childIdx++) {
+ const nextChild = children[childIdx]; // Write all the chunks up until the next child.
+
+ for (; chunkIdx < nextChild.index; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ r = flushSegment(request, destination, nextChild);
+ } // Finally just write all the remaining chunks
+
+
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ if (chunkIdx < chunks.length) {
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
+ }
+
+ return r;
+ }
+
+ default:
+ {
+ throw new Error('Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.');
+ }
+ }
+}
+
+function flushSegment(request, destination, segment) {
+ const boundary = segment.boundary;
+
+ if (boundary === null) {
+ // Not a suspense boundary.
+ return flushSubtree(request, destination, segment);
+ }
+
+ boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to
+ // emit the content or the fallback now.
+
+ if (boundary.status === CLIENT_RENDERED) {
+ // Emit a client rendered suspense boundary wrapper.
+ // We never queue the inner boundary so we'll never emit its content or partial segments.
+ writeStartClientRenderedSuspenseBoundary(destination, request.renderState, boundary.errorDigest); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndClientRenderedSuspenseBoundary(destination);
+ } else if (boundary.status !== COMPLETED) {
+ if (boundary.status === PENDING) {
+ // For pending boundaries we lazily assign an ID to the boundary
+ // and root segment.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ }
+
+ if (boundary.completedSegments.length > 0) {
+ // If this is at least partially complete, we can queue it to be partially emitted early.
+ request.partialBoundaries.push(boundary);
+ } // This boundary is still loading. Emit a pending suspense boundary wrapper.
+
+
+ const id = boundary.rootSegmentID;
+ writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else if (boundary.byteSize > request.progressiveChunkSize) {
+ // This boundary is large and will be emitted separately so that we can progressively show
+ // other content. We add it to the queue during the flush because we have to ensure that
+ // the parent flushes first so that there's something to inject it into.
+ // We also have to make sure that it's emitted into the queue in a deterministic slot.
+ // I.e. we can't insert it here when it completes.
+ // Assign an ID to refer to the future content by.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper.
+
+ writeStartPendingSuspenseBoundary(destination, request.renderState, boundary.rootSegmentID); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else {
+ {
+ hoistResources(request.renderState, boundary.resources);
+ } // We can inline this boundary's content as a complete boundary.
+
+
+ writeStartCompletedSuspenseBoundary(destination);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length !== 1) {
+ throw new Error('A previously unvisited boundary must have exactly one root segment. This is a bug in React.');
+ }
+
+ const contentSegment = completedSegments[0];
+ flushSegment(request, destination, contentSegment);
+ return writeEndCompletedSuspenseBoundary(destination);
+ }
+}
+
+function flushClientRenderedBoundary(request, destination, boundary) {
+ return writeClientRenderBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack);
+}
+
+function flushSegmentContainer(request, destination, segment) {
+ writeStartSegment(destination, request.renderState, segment.parentFormatContext, segment.id);
+ flushSegment(request, destination, segment);
+ return writeEndSegment(destination, segment.parentFormatContext);
+}
+
+function flushCompletedBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+ flushPartiallyCompletedSegment(request, destination, boundary, segment);
+ }
+
+ completedSegments.length = 0;
+
+ {
+ writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+
+ return writeCompletedBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.resources);
+}
+
+function flushPartialBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+
+ if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) {
+ i++;
+ completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority
+ // might want to write later.
+
+ return false;
+ }
+ }
+
+ completedSegments.splice(0, i);
+
+ {
+ // The way this is structured we only write resources for partial boundaries
+ // if there is no backpressure. Later before we complete the boundary we
+ // will write resources regardless of backpressure before we emit the
+ // completion instruction
+ return writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+}
+
+function flushPartiallyCompletedSegment(request, destination, boundary, segment) {
+ if (segment.status === FLUSHED) {
+ // We've already flushed this inline.
+ return true;
+ }
+
+ const segmentID = segment.id;
+
+ if (segmentID === -1) {
+ // This segment wasn't previously referred to. This happens at the root of
+ // a boundary. We make kind of a leap here and assume this is the root.
+ const rootSegmentID = segment.id = boundary.rootSegmentID;
+
+ if (rootSegmentID === -1) {
+ throw new Error('A root segment ID must have been assigned by now. This is a bug in React.');
+ }
+
+ return flushSegmentContainer(request, destination, segment);
+ } else if (segmentID === boundary.rootSegmentID) {
+ // When we emit postponed boundaries, we might have assigned the ID already
+ // but it's still the root segment so we can't inject it into the parent yet.
+ return flushSegmentContainer(request, destination, segment);
+ } else {
+ flushSegmentContainer(request, destination, segment);
+ return writeCompletedSegmentInstruction(destination, request.resumableState, request.renderState, segmentID);
+ }
+}
+
+function flushCompletedQueues(request, destination) {
+ beginWriting();
+
+ try {
+ // The structure of this is to go through each queue one by one and write
+ // until the sink tells us to stop. When we should stop, we still finish writing
+ // that item fully and then yield. At that point we remove the already completed
+ // items up until the point we completed them.
+ let i;
+ const completedRootSegment = request.completedRootSegment;
+
+ if (completedRootSegment !== null) {
+ if (completedRootSegment.status === POSTPONED) {
+ // We postponed the root, so we write nothing.
+ return;
+ } else if (request.pendingRootTasks === 0) {
+ if (enableFloat) {
+ writePreamble(destination, request.resumableState, request.renderState, request.allPendingTasks === 0 && request.trackedPostpones === null);
+ }
+
+ flushSegment(request, destination, completedRootSegment);
+ request.completedRootSegment = null;
+ writeCompletedRoot(destination, request.renderState, request.resumableState);
+ } else {
+ // We haven't flushed the root yet so we don't need to check any other branches further down
+ return;
+ }
+ }
+
+ if (enableFloat) {
+ writeHoistables(destination, request.resumableState, request.renderState);
+ } // We emit client rendering instructions for already emitted boundaries first.
+ // This is so that we can signal to the client to start client rendering them as
+ // soon as possible.
+
+
+ const clientRenderedBoundaries = request.clientRenderedBoundaries;
+
+ for (i = 0; i < clientRenderedBoundaries.length; i++) {
+ const boundary = clientRenderedBoundaries[i];
+
+ if (!flushClientRenderedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ clientRenderedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries
+ // that are completely done since we can actually show them, than it is to emit
+ // any individual segments from a partially complete boundary.
+
+ const completedBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < completedBoundaries.length; i++) {
+ const boundary = completedBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ completedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before
+ // we continue with lower priorities.
+
+ completeWriting(destination);
+ beginWriting(destination); // TODO: Here we'll emit data used by hydration.
+ // Next we emit any segments of any boundaries that are partially complete
+ // but not deeply complete.
+
+ const partialBoundaries = request.partialBoundaries;
+
+ for (i = 0; i < partialBoundaries.length; i++) {
+ const boundary = partialBoundaries[i];
+
+ if (!flushPartialBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ partialBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had
+ // boundaries added to it in case they were too larged to be inlined.
+ // New ones might be added in this loop.
+
+ const largeBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < largeBoundaries.length; i++) {
+ const boundary = largeBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ largeBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ largeBoundaries.splice(0, i);
+ } finally {
+ if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because
+ // either they have pending task or they're complete.
+ ) {
+ request.flushScheduled = false;
+
+ {
+ // We write the trailing tags but only if don't have any data to resume.
+ // If we need to resume we'll write the postamble in the resume instead.
+ if (request.trackedPostpones === null) {
+ writePostamble(destination, request.resumableState);
+ }
+ }
+
+ completeWriting(destination);
+ flushBuffered(destination);
+
+
+ close(destination); // We need to stop flowing now because we do not want any async contexts which might call
+ // float methods to initiate any flushes after this point
+
+ stopFlowing(request);
+ } else {
+ completeWriting(destination);
+ flushBuffered(destination);
+ }
+ }
+}
+
+function startWork(request) {
+ request.flushScheduled = request.destination !== null;
+
+ {
+ scheduleWork(() => requestStorage.run(request, performWork, request));
+ }
+
+ if (request.trackedPostpones === null) {
+ // this is either a regular render or a resume. For regular render we want
+ // to call emitEarlyPreloads after the first performWork because we want
+ // are responding to a live request and need to balance sending something early
+ // (i.e. don't want for the shell to finish) but we need something to send.
+ // The only implementation of this is for DOM at the moment and during resumes nothing
+ // actually emits but the code paths here are the same.
+ // During a prerender we don't want to be too aggressive in emitting early preloads
+ // because we aren't responding to a live request and we can wait for the prerender to
+ // postpone before we emit anything.
+ {
+ scheduleWork(() => requestStorage.run(request, enqueueEarlyPreloadsAfterInitialWork, request));
+ }
+ }
+}
+
+function enqueueEarlyPreloadsAfterInitialWork(request) {
+ const shellComplete = request.pendingRootTasks === 0;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+
+function enqueueFlush(request) {
+ if (request.flushScheduled === false && // If there are pinged tasks we are going to flush anyway after work completes
+ request.pingedTasks.length === 0 && // If there is no destination there is nothing we can flush to. A flush will
+ // happen when we start flowing again
+ request.destination !== null) {
+ request.flushScheduled = true;
+ scheduleWork(() => {
+ // We need to existence check destination again here because it might go away
+ // in between the enqueueFlush call and the work execution
+ const destination = request.destination;
+
+ if (destination) {
+ flushCompletedQueues(request, destination);
+ } else {
+ request.flushScheduled = false;
+ }
+ });
+ }
+} // This function is intented to only be called during the pipe function for the Node builds.
+// The reason we need this is because `renderToPipeableStream` is the only API which allows
+// you to start flowing before the shell is complete and we've had a chance to emit early
+// preloads already. This is really just defensive programming to ensure that we give hosts an
+// opportunity to flush early preloads before streaming begins in case they are in an environment
+// that only supports a single call to emitEarlyPreloads like the DOM renderers. It's unfortunate
+// to put this Node only function directly in ReactFizzServer but it'd be more ackward to factor it
+// by moving the implementation into ReactServerStreamConfigNode and even then we may not be able to
+// eliminate all the wasted branching.
+
+
+function prepareForStartFlowingIfBeforeAllReady(request) {
+ const shellComplete = request.trackedPostpones === null ? // Render Request, we define shell complete by the pending root tasks
+ request.pendingRootTasks === 0 : // Prerender Request, we define shell complete by completedRootSegemtn
+ request.completedRootSegment === null ? request.pendingRootTasks === 0 : request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+function startFlowing(request, destination) {
+ if (request.status === CLOSING) {
+ request.status = CLOSED;
+ closeWithError(destination, request.fatalError);
+ return;
+ }
+
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ if (request.destination !== null) {
+ // We're already flowing.
+ return;
+ }
+
+ request.destination = destination;
+
+ try {
+ flushCompletedQueues(request, destination);
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function stopFlowing(request) {
+ request.destination = null;
+} // This is called to early terminate a request. It puts all pending boundaries in client rendered state.
+
+function abort(request, reason) {
+ try {
+ const abortableTasks = request.abortableTasks;
+
+ if (abortableTasks.size > 0) {
+ const error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason;
+ abortableTasks.forEach(task => abortTask(task, request, error));
+ abortableTasks.clear();
+ }
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function flushResources(request) {
+ enqueueFlush(request);
+}
+function getFormState(request) {
+ return request.formState;
+}
+function getResumableState(request) {
+ return request.resumableState;
+}
+function getRenderState(request) {
+ return request.renderState;
+}
+
+function addToReplayParent(node, parentKeyPath, trackedPostpones) {
+ if (parentKeyPath === null) {
+ trackedPostpones.rootNodes.push(node);
+ } else {
+ const workingMap = trackedPostpones.workingMap;
+ let parentNode = workingMap.get(parentKeyPath);
+
+ if (parentNode === undefined) {
+ parentNode = [parentKeyPath[1], parentKeyPath[2], [], null];
+ workingMap.set(parentKeyPath, parentNode);
+ addToReplayParent(parentNode, parentKeyPath[0], trackedPostpones);
+ }
+
+ parentNode[2].push(node);
+ }
+} // Returns the state of a postponed request or null if nothing was postponed.
+
+
+function getPostponedState(request) {
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones === null || trackedPostpones.rootNodes.length === 0 && trackedPostpones.rootSlots === null) {
+ // Reset. Let the flushing behave as if we completed the whole document.
+ request.trackedPostpones = null;
+ return null;
+ }
+
+ if (request.completedRootSegment !== null && request.completedRootSegment.status === POSTPONED) {
+ // We postponed the root so we didn't flush anything.
+ resetResumableState(request.resumableState, request.renderState);
+ }
+
+ return {
+ nextSegmentId: request.nextSegmentId,
+ rootFormatContext: request.rootFormatContext,
+ progressiveChunkSize: request.progressiveChunkSize,
+ resumableState: request.resumableState,
+ replayNodes: trackedPostpones.rootNodes,
+ replaySlots: trackedPostpones.rootSlots
+ };
+}
+
+function createDrainHandler(destination, request) {
+ return () => startFlowing(request, destination);
+}
+
+function createCancelHandler(request, reason) {
+ return () => {
+ stopFlowing(request); // eslint-disable-next-line react-internal/prod-error-codes
+
+ abort(request, new Error(reason));
+ };
+}
+
+function createRequestImpl(children, options) {
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ return createRequest(children, resumableState, createRenderState(resumableState, options ? options.nonce : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, options ? options.onHeaders : undefined, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, options ? options.onAllReady : undefined, options ? options.onShellReady : undefined, options ? options.onShellError : undefined, undefined, options ? options.onPostpone : undefined, options ? options.formState : undefined);
+}
+
+function renderToPipeableStream(children, options) {
+ const request = createRequestImpl(children, options);
+ let hasStartedFlowing = false;
+ startWork(request);
+ return {
+ pipe(destination) {
+ if (hasStartedFlowing) {
+ throw new Error('React currently only supports piping to one writable stream.');
+ }
+
+ hasStartedFlowing = true;
+ prepareForStartFlowingIfBeforeAllReady(request);
+ startFlowing(request, destination);
+ destination.on('drain', createDrainHandler(destination, request));
+ destination.on('error', createCancelHandler(request, 'The destination stream errored while writing data.'));
+ destination.on('close', createCancelHandler(request, 'The destination stream closed early.'));
+ return destination;
+ },
+
+ abort(reason) {
+ abort(request, reason);
+ }
+
+ };
+}
+
+function resumeRequestImpl(children, postponedState, options) {
+ return resumeRequest(children, postponedState, resumeRenderState(postponedState.resumableState, options ? options.nonce : undefined), options ? options.onError : undefined, options ? options.onAllReady : undefined, options ? options.onShellReady : undefined, options ? options.onShellError : undefined, undefined, options ? options.onPostpone : undefined);
+}
+
+function resumeToPipeableStream(children, postponedState, options) {
+ const request = resumeRequestImpl(children, postponedState, options);
+ let hasStartedFlowing = false;
+ startWork(request);
+ return {
+ pipe(destination) {
+ if (hasStartedFlowing) {
+ throw new Error('React currently only supports piping to one writable stream.');
+ }
+
+ hasStartedFlowing = true;
+ startFlowing(request, destination);
+ destination.on('drain', createDrainHandler(destination, request));
+ destination.on('error', createCancelHandler(request, 'The destination stream errored while writing data.'));
+ destination.on('close', createCancelHandler(request, 'The destination stream closed early.'));
+ return destination;
+ },
+
+ abort(reason) {
+ abort(request, reason);
+ }
+
+ };
+}
+
+function createFakeWritable(readable) {
+ // The current host config expects a Writable so we create
+ // a fake writable for now to push into the Readable.
+ return {
+ write(chunk) {
+ return readable.push(chunk);
+ },
+
+ end() {
+ readable.push(null);
+ },
+
+ destroy(error) {
+ readable.destroy(error);
+ }
+
+ };
+}
+
+function prerenderToNodeStream(children, options) {
+ return new Promise((resolve, reject) => {
+ const onFatalError = reject;
+
+ function onAllReady() {
+ const readable = new stream.Readable({
+ read() {
+ startFlowing(request, writable);
+ }
+
+ });
+ const writable = createFakeWritable(readable);
+ const result = {
+ postponed: getPostponedState(request),
+ prelude: readable
+ };
+ resolve(result);
+ }
+
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ const request = createPrerenderRequest(children, resumableState, createRenderState(resumableState, undefined, // nonce is not compatible with prerendered bootstrap scripts
+ options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, options ? options.onHeaders : undefined, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, onAllReady, undefined, undefined, onFatalError, options ? options.onPostpone : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+exports.prerenderToNodeStream = prerenderToNodeStream;
+exports.renderToPipeableStream = renderToPipeableStream;
+exports.resumeToPipeableStream = resumeToPipeableStream;
+exports.version = ReactVersion;
\ No newline at end of file
diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.production.min.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.production.min.js
index a30bb28865ee6..f001509504061 100644
--- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.production.min.js
+++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.production.min.js
@@ -1,12 +1,12 @@
-/**
- * @license React
- * react-dom-server.node.production.min.js
- *
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
+/*
+ React
+ react-dom-server.node.production.min.js
+
+ Copyright (c) Meta Platforms, Inc. and affiliates.
+
+ This source code is licensed under the MIT license found in the
+ LICENSE file in the root directory of this source tree.
+*/
'use strict';var aa=require("util"),ba=require("crypto"),ca=require("async_hooks"),fa=require("next/dist/compiled/react-experimental"),ha=require("react-dom"),ia=require("stream");function ja(a){"function"===typeof a.flush&&a.flush()}var l=null,n=0,na=!0;
function u(a,b){if("string"===typeof b){if(0!==b.length)if(2048<3*b.length)0 '),sb=x("');
+const startScriptSrc = stringToPrecomputedChunk('');
+/**
+ * This escaping function is designed to work with bootstrapScriptContent and importMap only.
+ * because we know we are escaping the entire script. We can avoid for instance
+ * escaping html comment string sequences that are valid javascript as well because
+ * if there are no sebsequent '); // Since we store headers as strings we deal with their length in utf16 code units
+// rather than visual characters or the utf8 encoding that is used for most binary
+// serialization. Some common HTTP servers only allow for headers to be 4kB in length.
+// We choose a default length that is likely to be well under this already limited length however
+// pathological cases may still cause the utf-8 encoding of the headers to approach this limit.
+// It should also be noted that this maximum is a soft maximum. we have not reached the limit we will
+// allow one more header to be captured which means in practice if the limit is approached it will be exceeded
+
+const DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep track of what we've already written so we can refer back to it.
+// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
+// is set, the server will send instructions via data attributes (instead of inline scripts)
+
+function createRenderState$1(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+ const inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const completeSegmentData1 = stringToPrecomputedChunk('');
+const completeBoundaryData1 = stringToPrecomputedChunk('');
+const clientRenderData1 = stringToPrecomputedChunk('
+ return writeChunkAndReturn(destination, clientRenderDataEnd);
+ }
+}
+const regexForJSStringsInInstructionScripts = /[<\u2028\u2029]/g;
+
+function escapeJSStringsForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInInstructionScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const regexForJSStringsInScripts = /[&><\u2028\u2029]/g;
+
+function escapeJSObjectForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '&':
+ return '\\u0026';
+
+ case '>':
+ return '\\u003e';
+
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(''); // Tracks whether the boundary currently flushing is flushign style tags or has any
+// stylesheet dependencies not flushed in the Preamble.
+
+let currentlyRenderingBoundaryHasStylesToHoist = false; // Acts as a return value for the forEach execution of style tag flushing.
+
+let destinationHasCapacity = true;
+
+function flushStyleTagsLateForBoundary(styleQueue) {
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs;
+
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, lateStyleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ writeChunk(this, lateStyleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, lateStyleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ destinationHasCapacity = writeChunkAndReturn(this, lateStyleTagTemplateClose); // We wrote style tags for this boundary and we may need to emit a script
+ // to hoist them.
+
+ currentlyRenderingBoundaryHasStylesToHoist = true; // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function hasStylesToHoist(stylesheet) {
+ // We need to reveal boundaries with styles whenever a stylesheet it depends on is either
+ // not flushed or flushed after the preamble (shell).
+ if (stylesheet.state !== PREAMBLE) {
+ currentlyRenderingBoundaryHasStylesToHoist = true;
+ return true;
+ }
+
+ return false;
+}
+
+function writeResourcesForBoundary(destination, boundaryResources, renderState) {
+ // Reset these on each invocation, they are only safe to read in this function
+ currentlyRenderingBoundaryHasStylesToHoist = false;
+ destinationHasCapacity = true; // Flush style tags for each precedence this boundary depends on
+
+ boundaryResources.styles.forEach(flushStyleTagsLateForBoundary, destination); // Determine if this boundary has stylesheets that need to be awaited upon completion
+
+ boundaryResources.stylesheets.forEach(hasStylesToHoist);
+
+ if (currentlyRenderingBoundaryHasStylesToHoist) {
+ renderState.stylesToHoist = true;
+ }
+
+ return destinationHasCapacity;
+}
+
+function flushResource(resource) {
+ for (let i = 0; i < resource.length; i++) {
+ writeChunk(this, resource[i]);
+ }
+
+ resource.length = 0;
+}
+
+const stylesheetFlushingQueue = [];
+
+function flushStyleInPreamble(stylesheet, key, map) {
+ // We still need to encode stylesheet chunks
+ // because unlike most Hoistables and Resources we do not eagerly encode
+ // them during render. This is because if we flush late we have to send a
+ // different encoding and we don't want to encode multiple times
+ pushLinkImpl(stylesheetFlushingQueue, stylesheet.props);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ stylesheet.state = PREAMBLE;
+}
+
+const styleTagResourceOpen1 = stringToPrecomputedChunk('');
+
+function flushStylesInPreamble(styleQueue, precedence) {
+ const hasStylesheets = styleQueue.sheets.size > 0;
+ styleQueue.sheets.forEach(flushStyleInPreamble, this);
+ styleQueue.sheets.clear();
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs; // If we don't emit any stylesheets at this precedence we still need to maintain the precedence
+ // order so even if there are no rules for style tags at this precedence we emit an empty style
+ // tag with the data-precedence attribute
+
+ if (!hasStylesheets || hrefs.length) {
+ writeChunk(this, styleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, styleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ }
+
+ writeChunk(this, styleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ writeChunk(this, styleTagResourceClose); // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function preloadLateStyle(stylesheet) {
+ if (stylesheet.state === PENDING$1) {
+ stylesheet.state = PRELOADED;
+ const preloadProps = preloadAsStylePropsFromProps(stylesheet.props.href, stylesheet.props);
+ pushLinkImpl(stylesheetFlushingQueue, preloadProps);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ }
+}
+
+function preloadLateStyles(styleQueue) {
+ styleQueue.sheets.forEach(preloadLateStyle, this);
+ styleQueue.sheets.clear();
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+
+function writePreamble(destination, resumableState, renderState, willFlushAllSegments) {
+ // This function must be called exactly once on every request
+ if (!willFlushAllSegments && renderState.externalRuntimeScript) {
+ // If the root segment is incomplete due to suspended tasks
+ // (e.g. willFlushAllSegments = false) and we are using data
+ // streaming format, ensure the external runtime is sent.
+ // (User code could choose to send this even earlier by calling
+ // preinit(...), if they know they will suspend).
+ const _renderState$external = renderState.externalRuntimeScript,
+ src = _renderState$external.src,
+ chunks = _renderState$external.chunks;
+ internalPreinitScript(resumableState, renderState, src, chunks);
+ }
+
+ const htmlChunks = renderState.htmlChunks;
+ const headChunks = renderState.headChunks;
+ let i = 0; // Emit open tags before Hoistables and Resources
+
+ if (htmlChunks) {
+ // We have an to emit as part of the preamble
+ for (i = 0; i < htmlChunks.length; i++) {
+ writeChunk(destination, htmlChunks[i]);
+ }
+
+ if (headChunks) {
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } else {
+ // We did not render a head but we emitted an so we emit one now
+ writeChunk(destination, startChunkForTag('head'));
+ writeChunk(destination, endOfStartTag);
+ }
+ } else if (headChunks) {
+ // We do not have an but we do have a
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } // Emit high priority Hoistables
+
+
+ const charsetChunks = renderState.charsetChunks;
+
+ for (i = 0; i < charsetChunks.length; i++) {
+ writeChunk(destination, charsetChunks[i]);
+ }
+
+ charsetChunks.length = 0; // emit preconnect resources
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Flush unblocked stylesheets by precedence
+
+ renderState.styles.forEach(flushStylesInPreamble, destination);
+ const importMapChunks = renderState.importMapChunks;
+
+ for (i = 0; i < importMapChunks.length; i++) {
+ writeChunk(destination, importMapChunks[i]);
+ }
+
+ importMapChunks.length = 0;
+ renderState.bootstrapScripts.forEach(flushResource, destination);
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0; // Flush closing head if necessary
+
+ if (htmlChunks && headChunks === null) {
+ // We have an rendered but no rendered. We however inserted
+ // a up above so we need to emit the now. This is safe because
+ // if the main content contained the it would also have provided a
+ // . This means that all the content inside is either or
+ // invalid HTML
+ writeChunk(destination, endChunkForTag('head'));
+ }
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+function writeHoistables(destination, resumableState, renderState) {
+ let i = 0; // Emit high priority Hoistables
+ // We omit charsetChunks because we have already sent the shell and if it wasn't
+ // already sent it is too late now.
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Preload any stylesheets. these will emit in a render instruction that follows this
+ // but we want to kick off preloading as soon as possible
+
+ renderState.styles.forEach(preloadLateStyles, destination); // We only hoist importmaps that are configured through createResponse and that will
+ // always flush in the preamble. Generally we don't expect people to render them as
+ // tags when using React but if you do they are going to be treated like regular inline
+ // scripts and flush after other hoistables which is problematic
+ // bootstrap scripts should flush above script priority but these can only flush in the preamble
+ // so we elide the code here for performance
+
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0;
+}
+function writePostamble(destination, resumableState) {
+ if (resumableState.hasBody) {
+ writeChunk(destination, endChunkForTag('body'));
+ }
+
+ if (resumableState.hasHtml) {
+ writeChunk(destination, endChunkForTag('html'));
+ }
+}
+const arrayFirstOpenBracket = stringToPrecomputedChunk('[');
+const arraySubsequentOpenBracket = stringToPrecomputedChunk(',[');
+const arrayInterstitial = stringToPrecomputedChunk(',');
+const arrayCloseBracket = stringToPrecomputedChunk(']'); // This function writes a 2D array of strings to be embedded in javascript.
+// E.g.
+// [["JS_escaped_string1", "JS_escaped_string2"]]
+
+function writeStyleResourceDependenciesInJS(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInJS(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInJS(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInJS(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+}
+
+function writeStyleResourceDependencyInJS(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedPrecedence)));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw Error(formatProdErrorMessage(399, 'link'));
+
+ default:
+ writeStyleResourceAttributeInJS(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInJS(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeName)));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeValue)));
+} // This function writes a 2D array of strings to be embedded in an attribute
+// value and read with JSON.parse in ReactDOMServerExternalRuntime.js
+// E.g.
+// [["JSON_escaped_string1", "JSON_escaped_string2"]]
+
+
+function writeStyleResourceDependenciesInAttr(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInAttr(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInAttr(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInAttr(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+}
+
+function writeStyleResourceDependencyInAttr(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedPrecedence))));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw Error(formatProdErrorMessage(399, 'link'));
+
+ default:
+ writeStyleResourceAttributeInAttr(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInAttr(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeName))));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeValue))));
+}
+/**
+ * Resources
+ */
+
+
+const PENDING$1 = 0;
+const PRELOADED = 1;
+const PREAMBLE = 2;
+const LATE = 3;
+function createBoundaryResources() {
+ return {
+ styles: new Set(),
+ stylesheets: new Set()
+ };
+}
+function setCurrentlyRenderingBoundaryResourcesTarget(renderState, boundaryResources) {
+ renderState.boundaryResources = boundaryResources;
+}
+
+function getResourceKey(href) {
+ return href;
+}
+
+function getImageResourceKey(href, imageSrcSet, imageSizes) {
+ if (imageSrcSet) {
+ return imageSrcSet + '\n' + (imageSizes || '');
+ }
+
+ return href;
+}
+
+function prefetchDNS(href) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const key = getResourceKey(href);
+
+ if (!resumableState.dnsResources.hasOwnProperty(key)) {
+ resumableState.dnsResources[key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPrefetchDNSAsHeader(href), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this as resettable in case we are prerendering and postpone in the Shell
+ renderState.resets.dns[key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ // Encode as element
+ const resource = [];
+ pushLinkImpl(resource, {
+ href,
+ rel: 'dns-prefetch'
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preconnect(href, crossOrigin) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const bucket = crossOrigin === 'use-credentials' ? 'credentials' : typeof crossOrigin === 'string' ? 'anonymous' : 'default';
+ const key = getResourceKey(href);
+
+ if (!resumableState.connectResources[bucket].hasOwnProperty(key)) {
+ resumableState.connectResources[bucket][key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreconnectAsHeader(href, crossOrigin), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this in resettableState in case we are prerending and postpone in the Shell
+ renderState.resets.connect[bucket][key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ const resource = [];
+ pushLinkImpl(resource, {
+ rel: 'preconnect',
+ href,
+ crossOrigin
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preload(href, as, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (as && href) {
+ switch (as) {
+ case 'image':
+ {
+ let imageSrcSet, imageSizes, fetchPriority;
+
+ if (options) {
+ imageSrcSet = options.imageSrcSet;
+ imageSizes = options.imageSizes;
+ fetchPriority = options.fetchPriority;
+ }
+
+ const key = getImageResourceKey(href, imageSrcSet, imageSizes);
+
+ if (resumableState.imageResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resumableState.imageResources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && fetchPriority === 'high' && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit a preload as a header so we
+ // track this to make sure we don't reset it.
+ renderState.resets.image[key] = PRELOAD_NO_CREDS;
+
+ if (headers.highImagePreloads) {
+ headers.highImagePreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.highImagePreloads += header;
+ } else {
+ // If we don't have headers to write to we have to encode as elements to flush in the head
+ // When we have imageSrcSet the browser probably cannot load the right version from headers
+ // (this should be verified by testing). For now we assume these need to go in the head
+ // as elements even if headers are available.
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ // There is a bug in Safari where imageSrcSet is not respected on preload links
+ // so we omit the href here if we have imageSrcSet b/c safari will load the wrong image.
+ // This harms older browers that do not support imageSrcSet by making their preloads not work
+ // but this population is shrinking fast and is already small so we accept this tradeoff.
+ href: imageSrcSet ? undefined : href,
+ as
+ }, options));
+
+ if (fetchPriority === 'high') {
+ renderState.highImagePreloads.add(resource);
+ } else {
+ renderState.bulkPreloads.add(resource); // Stash the resource in case we need to promote it to higher priority
+ // when an img tag is rendered
+
+ renderState.preloads.images.set(key, resource);
+ }
+ }
+
+ break;
+ }
+
+ case 'style':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.styleResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.styleResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.stylesheets.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ break;
+ }
+
+ case 'script':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.scriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ renderState.preloads.scripts.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.scriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ break;
+ }
+
+ default:
+ {
+ const key = getResourceKey(href);
+ const hasAsType = resumableState.unknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.unknownResources[as] = resources;
+ }
+
+ resources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && as === 'font' && ( // We compute the header here because we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit this preload so we
+ // track it here to prevent it from being reset.
+ renderState.resets.font[key] = PRELOAD_NO_CREDS;
+
+ if (headers.fontPreloads) {
+ headers.fontPreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.fontPreloads += header;
+ } else {
+ // We either don't have headers or we are preloading something that does
+ // not warrant elevated priority so we encode as an element.
+ const resource = [];
+
+ const props = assign({
+ rel: 'preload',
+ href,
+ as
+ }, options);
+
+ pushLinkImpl(resource, props);
+
+ switch (as) {
+ case 'font':
+ renderState.fontPreloads.add(resource);
+ break;
+ // intentional fall through
+
+ default:
+ renderState.bulkPreloads.add(resource);
+ }
+ }
+ }
+ } // If we got this far we created a new resource
+
+
+ flushResources(request);
+ }
+}
+
+function preloadModule(href, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ const key = getResourceKey(href);
+ const as = options && typeof options.as === 'string' ? options.as : 'script';
+ let resource;
+
+ switch (as) {
+ case 'script':
+ {
+ if (resumableState.moduleScriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resource = [];
+ resumableState.moduleScriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.moduleScripts.set(key, resource);
+ break;
+ }
+
+ default:
+ {
+ const hasAsType = resumableState.moduleUnknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.moduleUnknownResources[as] = resources;
+ }
+
+ resource = [];
+ resources[key] = PRELOAD_NO_CREDS;
+ }
+ }
+
+ pushLinkImpl(resource, assign({
+ rel: 'modulepreload',
+ href
+ }, options));
+ renderState.bulkPreloads.add(resource); // If we got this far we created a new resource
+
+ flushResources(request);
+ }
+}
+
+function preinitStyle(href, precedence, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ precedence = precedence || 'default';
+ const key = getResourceKey(href);
+ let styleQueue = renderState.styles.get(precedence);
+ const hasKey = resumableState.styleResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.styleResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.styleResources[key] = EXISTS; // If this is the first time we've encountered this precedence we need
+ // to create a StyleQueue
+
+ if (!styleQueue) {
+ styleQueue = {
+ precedence: stringToChunk(escapeTextForBrowser(precedence)),
+ rules: [],
+ hrefs: [],
+ sheets: new Map()
+ };
+ renderState.styles.set(precedence, styleQueue);
+ }
+
+ const resource = {
+ state: PENDING$1,
+ props: assign({
+ rel: 'stylesheet',
+ href,
+ 'data-precedence': precedence
+ }, options)
+ };
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(resource.props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.stylesheets.get(key);
+
+ if (preloadResource && preloadResource.length > 0) {
+ // The Preload for this resource was created in this render pass and has not flushed yet so
+ // we need to clear it to avoid it flushing.
+ preloadResource.length = 0;
+ } else {
+ // Either the preload resource from this render already flushed in this render pass
+ // or the preload flushed in a prior pass (prerender). In either case we need to mark
+ // this resource as already having been preloaded.
+ resource.state = PRELOADED;
+ }
+ } // We add the newly created resource to our StyleQueue and if necessary
+ // track the resource with the currently rendering boundary
+
+
+ styleQueue.sheets.set(key, resource); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+ }
+}
+
+function preinitScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.scriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.scriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.scriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.scripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+}
+
+function preinitModuleScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.moduleScriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.moduleScriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.moduleScriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ type: 'module',
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.moduleScripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+} // This function is only safe to call at Request start time since it assumes
+// that each module has not already been preloaded. If we find a need to preload
+// scripts at any other point in time we will need to check whether the preload
+// already exists and not assume it
+
+
+function preloadBootstrapScriptOrModule(resumableState, renderState, href, props) {
+
+ const key = getResourceKey(href);
+ // used to preinit the resource. If a script can be preinited then it shouldn't
+ // be a bootstrap script/module and if it is a bootstrap script/module then it
+ // must not be safe to emit early. To avoid possibly allowing for preinits of
+ // bootstrap scripts/modules we occlude these keys.
+
+
+ resumableState.scriptResources[key] = EXISTS;
+ resumableState.moduleScriptResources[key] = EXISTS;
+ const resource = [];
+ pushLinkImpl(resource, props);
+ renderState.bootstrapScripts.add(resource);
+}
+
+function internalPreinitScript(resumableState, renderState, src, chunks) {
+ const key = getResourceKey(src);
+
+ if (!resumableState.scriptResources.hasOwnProperty(key)) {
+ const resource = chunks;
+ resumableState.scriptResources[key] = EXISTS;
+ renderState.scripts.add(resource);
+ }
+
+ return;
+}
+
+function preloadAsStylePropsFromProps(href, props) {
+ return {
+ rel: 'preload',
+ as: 'style',
+ href: href,
+ crossOrigin: props.crossOrigin,
+ fetchPriority: props.fetchPriority,
+ integrity: props.integrity,
+ media: props.media,
+ hrefLang: props.hrefLang,
+ referrerPolicy: props.referrerPolicy
+ };
+}
+
+function stylesheetPropsFromRawProps(rawProps) {
+ return assign({}, rawProps, {
+ 'data-precedence': rawProps.precedence,
+ precedence: null
+ });
+}
+
+function adoptPreloadCredentials(target, preloadState) {
+ if (target.crossOrigin == null) target.crossOrigin = preloadState[0];
+ if (target.integrity == null) target.integrity = preloadState[1];
+}
+
+function getPrefetchDNSAsHeader(href) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ return "<" + escapedHref + ">; rel=dns-prefetch";
+}
+
+function getPreconnectAsHeader(href, crossOrigin) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ let value = "<" + escapedHref + ">; rel=preconnect";
+
+ if (typeof crossOrigin === 'string') {
+ const escapedCrossOrigin = escapeStringForLinkHeaderQuotedParamValueContext(crossOrigin);
+ value += "; crossorigin=\"" + escapedCrossOrigin + "\"";
+ }
+
+ return value;
+}
+
+function getPreloadAsHeader(href, as, params) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ const escapedAs = escapeStringForLinkHeaderQuotedParamValueContext(as);
+ let value = "<" + escapedHref + ">; rel=preload; as=\"" + escapedAs + "\"";
+
+ for (const paramName in params) {
+ if (hasOwnProperty.call(params, paramName)) {
+ const paramValue = params[paramName];
+
+ if (typeof paramValue === 'string') {
+ value += "; " + paramName.toLowerCase() + "=\"" + escapeStringForLinkHeaderQuotedParamValueContext(paramValue) + "\"";
+ }
+ }
+ }
+
+ return value;
+}
+
+function getStylesheetPreloadAsHeader(stylesheet) {
+ const props = stylesheet.props;
+ const preloadOptions = {
+ crossOrigin: props.crossOrigin,
+ integrity: props.integrity,
+ nonce: props.nonce,
+ type: props.type,
+ fetchPriority: props.fetchPriority,
+ referrerPolicy: props.referrerPolicy,
+ media: props.media
+ };
+ return getPreloadAsHeader(props.href, 'style', preloadOptions);
+} // This escaping function is only safe to use for href values being written into
+// a "Link" header in between `<` and `>` characters. The primary concern with the href is
+// to escape the bounding characters as well as new lines. This is unsafe to use in any other
+// context
+
+
+const regexForHrefInLinkHeaderURLContext = /[<>\r\n]/g;
+
+function escapeHrefForLinkHeaderURLContext(hrefInput) {
+
+ const coercedHref = '' + hrefInput;
+ return coercedHref.replace(regexForHrefInLinkHeaderURLContext, escapeHrefForLinkHeaderURLContextReplacer);
+}
+
+function escapeHrefForLinkHeaderURLContextReplacer(match) {
+ switch (match) {
+ case '<':
+ return '%3C';
+
+ case '>':
+ return '%3E';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+} // This escaping function is only safe to use for quoted param values in an HTTP header.
+// It is unsafe to use for any value not inside quote marks in parater value position.
+
+
+const regexForLinkHeaderQuotedParamValueContext = /["';,\r\n]/g;
+
+function escapeStringForLinkHeaderQuotedParamValueContext(value, name) {
+
+ const coerced = '' + value;
+ return coerced.replace(regexForLinkHeaderQuotedParamValueContext, escapeStringForLinkHeaderQuotedParamValueContextReplacer);
+}
+
+function escapeStringForLinkHeaderQuotedParamValueContextReplacer(match) {
+ switch (match) {
+ case '"':
+ return '%22';
+
+ case "'":
+ return '%27';
+
+ case ';':
+ return '%3B';
+
+ case ',':
+ return '%2C';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+}
+
+function hoistStyleQueueDependency(styleQueue) {
+ this.styles.add(styleQueue);
+}
+
+function hoistStylesheetDependency(stylesheet) {
+ this.stylesheets.add(stylesheet);
+}
+
+function hoistResources(renderState, source) {
+ const currentBoundaryResources = renderState.boundaryResources;
+
+ if (currentBoundaryResources) {
+ source.styles.forEach(hoistStyleQueueDependency, currentBoundaryResources);
+ source.stylesheets.forEach(hoistStylesheetDependency, currentBoundaryResources);
+ }
+} // This function is called at various times depending on whether we are rendering
+// or prerendering. In this implementation we only actually emit headers once and
+// subsequent calls are ignored. We track whether the request has a completed shell
+// to determine whether we will follow headers with a flush including stylesheets.
+// In the context of prerrender we don't have a completed shell when the request finishes
+// with a postpone in the shell. In the context of a render we don't have a completed shell
+// if this is called before the shell finishes rendering which usually will happen anytime
+// anything suspends in the shell.
+
+function emitEarlyPreloads(renderState, resumableState, shellComplete) {
+ const onHeaders = renderState.onHeaders;
+
+ if (onHeaders) {
+ const headers = renderState.headers;
+
+ if (headers) {
+ let linkHeader = headers.preconnects;
+
+ if (headers.fontPreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.fontPreloads;
+ }
+
+ if (headers.highImagePreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.highImagePreloads;
+ }
+
+ if (!shellComplete) {
+ // We use raw iterators because we want to be able to halt iteration
+ // We could refactor renderState to store these dually in arrays to
+ // make this more efficient at the cost of additional memory and
+ // write overhead. However this code only runs once per request so
+ // for now I consider this sufficient.
+ const queueIter = renderState.styles.values();
+
+ outer: for (let queueStep = queueIter.next(); headers.remainingCapacity > 0 && !queueStep.done; queueStep = queueIter.next()) {
+ const sheets = queueStep.value.sheets;
+ const sheetIter = sheets.values();
+
+ for (let sheetStep = sheetIter.next(); headers.remainingCapacity > 0 && !sheetStep.done; sheetStep = sheetIter.next()) {
+ const sheet = sheetStep.value;
+ const props = sheet.props;
+ const key = getResourceKey(props.href);
+ const header = getStylesheetPreloadAsHeader(sheet); // We mutate the capacity b/c we don't want to keep checking if later headers will fit.
+ // This means that a particularly long header might close out the header queue where later
+ // headers could still fit. We could in the future alter the behavior here based on prerender vs render
+ // since during prerender we aren't as concerned with pure runtime performance.
+
+ if ((headers.remainingCapacity -= header.length) >= 2) {
+ renderState.resets.style[key] = PRELOAD_NO_CREDS;
+
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += header; // We already track that the resource exists in resumableState however
+ // if the resumableState resets because we postponed in the shell
+ // which is what is happening in this branch if we are prerendering
+ // then we will end up resetting the resumableState. When it resets we
+ // want to record the fact that this stylesheet was already preloaded
+
+ renderState.resets.style[key] = typeof props.crossOrigin === 'string' || typeof props.integrity === 'string' ? [props.crossOrigin, props.integrity] : PRELOAD_NO_CREDS;
+ } else {
+ break outer;
+ }
+ }
+ }
+ }
+
+ if (linkHeader) {
+ onHeaders({
+ Link: linkHeader
+ });
+ } else {
+ // We still call this with no headers because a user may be using it as a signal that
+ // it React will not provide any headers
+ onHeaders({});
+ }
+
+ renderState.headers = null;
+ return;
+ }
+ }
+}
+
+function createRenderState(resumableState, generateStaticMarkup) {
+ const renderState = createRenderState$1(resumableState, undefined, undefined, undefined, undefined, undefined);
+ return {
+ // Keep this in sync with ReactFizzConfigDOM
+ placeholderPrefix: renderState.placeholderPrefix,
+ segmentPrefix: renderState.segmentPrefix,
+ boundaryPrefix: renderState.boundaryPrefix,
+ startInlineScript: renderState.startInlineScript,
+ htmlChunks: renderState.htmlChunks,
+ headChunks: renderState.headChunks,
+ externalRuntimeScript: renderState.externalRuntimeScript,
+ bootstrapChunks: renderState.bootstrapChunks,
+ onHeaders: renderState.onHeaders,
+ headers: renderState.headers,
+ resets: renderState.resets,
+ charsetChunks: renderState.charsetChunks,
+ preconnectChunks: renderState.preconnectChunks,
+ importMapChunks: renderState.importMapChunks,
+ preloadChunks: renderState.preloadChunks,
+ hoistableChunks: renderState.hoistableChunks,
+ preconnects: renderState.preconnects,
+ fontPreloads: renderState.fontPreloads,
+ highImagePreloads: renderState.highImagePreloads,
+ // usedImagePreloads: renderState.usedImagePreloads,
+ styles: renderState.styles,
+ bootstrapScripts: renderState.bootstrapScripts,
+ scripts: renderState.scripts,
+ bulkPreloads: renderState.bulkPreloads,
+ preloads: renderState.preloads,
+ boundaryResources: renderState.boundaryResources,
+ stylesToHoist: renderState.stylesToHoist,
+ // This is an extra field for the legacy renderer
+ generateStaticMarkup
+ };
+}
+
+const doctypeChunk = stringToPrecomputedChunk('');
+function pushTextInstance(target, text, renderState, textEmbedded) {
+ if (renderState.generateStaticMarkup) {
+ target.push(stringToChunk(escapeTextForBrowser(text)));
+ return false;
+ } else {
+ return pushTextInstance$1(target, text, renderState, textEmbedded);
+ }
+}
+function pushSegmentFinale(target, renderState, lastPushedText, textEmbedded) {
+ if (renderState.generateStaticMarkup) {
+ return;
+ } else {
+ return pushSegmentFinale$1(target, renderState, lastPushedText, textEmbedded);
+ }
+}
+function writeStartCompletedSuspenseBoundary(destination, renderState) {
+ if (renderState.generateStaticMarkup) {
+ // A completed boundary is done and doesn't need a representation in the HTML
+ // if we're not going to be hydrating it.
+ return true;
+ }
+
+ return writeStartCompletedSuspenseBoundary$1(destination);
+}
+function writeStartClientRenderedSuspenseBoundary(destination, renderState, // flushing these error arguments are not currently supported in this legacy streaming format.
+errorDigest, errorMessage, errorComponentStack) {
+ if (renderState.generateStaticMarkup) {
+ // A client rendered boundary is done and doesn't need a representation in the HTML
+ // since we'll never hydrate it. This is arguably an error in static generation.
+ return true;
+ }
+
+ return writeStartClientRenderedSuspenseBoundary$1(destination, renderState, errorDigest);
+}
+function writeEndCompletedSuspenseBoundary(destination, renderState) {
+ if (renderState.generateStaticMarkup) {
+ return true;
+ }
+
+ return writeEndCompletedSuspenseBoundary$1(destination);
+}
+function writeEndClientRenderedSuspenseBoundary(destination, renderState) {
+ if (renderState.generateStaticMarkup) {
+ return true;
+ }
+
+ return writeEndClientRenderedSuspenseBoundary$1(destination);
+}
+const NotPendingTransition = NotPending;
+
+// ATTENTION
+// When adding new symbols to this file,
+// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
+// The Symbol used to tag the ReactElement-like types.
+const REACT_ELEMENT_TYPE = Symbol.for('react.element');
+const REACT_PORTAL_TYPE = Symbol.for('react.portal');
+const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
+const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
+const REACT_PROFILER_TYPE = Symbol.for('react.profiler');
+const REACT_PROVIDER_TYPE = Symbol.for('react.provider');
+const REACT_CONTEXT_TYPE = Symbol.for('react.context');
+const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
+const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
+const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
+const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
+const REACT_MEMO_TYPE = Symbol.for('react.memo');
+const REACT_LAZY_TYPE = Symbol.for('react.lazy');
+const REACT_SCOPE_TYPE = Symbol.for('react.scope');
+const REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');
+const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
+const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');
+const REACT_CACHE_TYPE = Symbol.for('react.cache');
+const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value');
+const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
+const FAUX_ITERATOR_SYMBOL = '@@iterator';
+function getIteratorFn(maybeIterable) {
+ if (maybeIterable === null || typeof maybeIterable !== 'object') {
+ return null;
+ }
+
+ const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
+
+ if (typeof maybeIterator === 'function') {
+ return maybeIterator;
+ }
+
+ return null;
+}
+
+function getWrappedName(outerType, innerType, wrapperName) {
+ const displayName = outerType.displayName;
+
+ if (displayName) {
+ return displayName;
+ }
+
+ const functionName = innerType.displayName || innerType.name || '';
+ return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName;
+} // Keep in sync with react-reconciler/getComponentNameFromFiber
+
+
+function getContextName(type) {
+ return type.displayName || 'Context';
+} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+
+
+function getComponentNameFromType(type) {
+ if (type == null) {
+ // Host root, text node or just invalid type.
+ return null;
+ }
+
+ if (typeof type === 'function') {
+ return type.displayName || type.name || null;
+ }
+
+ if (typeof type === 'string') {
+ return type;
+ }
+
+ switch (type) {
+ case REACT_FRAGMENT_TYPE:
+ return 'Fragment';
+
+ case REACT_PORTAL_TYPE:
+ return 'Portal';
+
+ case REACT_PROFILER_TYPE:
+ return 'Profiler';
+
+ case REACT_STRICT_MODE_TYPE:
+ return 'StrictMode';
+
+ case REACT_SUSPENSE_TYPE:
+ return 'Suspense';
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ return 'SuspenseList';
+
+ case REACT_CACHE_TYPE:
+ {
+ return 'Cache';
+ }
+
+ }
+
+ if (typeof type === 'object') {
+ switch (type.$$typeof) {
+ case REACT_CONTEXT_TYPE:
+ const context = type;
+ return getContextName(context) + '.Consumer';
+
+ case REACT_PROVIDER_TYPE:
+ const provider = type;
+ return getContextName(provider._context) + '.Provider';
+
+ case REACT_FORWARD_REF_TYPE:
+ return getWrappedName(type, type.render, 'ForwardRef');
+
+ case REACT_MEMO_TYPE:
+ const outerName = type.displayName || null;
+
+ if (outerName !== null) {
+ return outerName;
+ }
+
+ return getComponentNameFromType(type.type) || 'Memo';
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyComponent = type;
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+
+ try {
+ return getComponentNameFromType(init(payload));
+ } catch (x) {
+ return null;
+ }
+ }
+
+ }
+ }
+
+ return null;
+}
+
+const emptyContextObject = {};
+
+function getMaskedContext(type, unmaskedContext) {
+ {
+ const contextTypes = type.contextTypes;
+
+ if (!contextTypes) {
+ return emptyContextObject;
+ }
+
+ const context = {};
+
+ for (const key in contextTypes) {
+ context[key] = unmaskedContext[key];
+ }
+
+ return context;
+ }
+}
+function processChildContext(instance, type, parentContext, childContextTypes) {
+ {
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
+ if (typeof instance.getChildContext !== 'function') {
+
+ return parentContext;
+ }
+
+ const childContext = instance.getChildContext();
+
+ for (const contextKey in childContext) {
+ if (!(contextKey in childContextTypes)) {
+ throw Error(formatProdErrorMessage(108, getComponentNameFromType(type) || 'Unknown', contextKey));
+ }
+ }
+
+ return assign({}, parentContext, childContext);
+ }
+}
+
+// Forming a reverse tree.
+// The structure of a context snapshot is an implementation of this file.
+// Currently, it's implemented as tracking the current active node.
+
+
+const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
+// This global (actually thread local) state represents what state all those "current",
+// fields are currently in.
+
+let currentActiveSnapshot = null;
+
+function popNode(prev) {
+ {
+ prev.context._currentValue2 = prev.parentValue;
+ }
+}
+
+function pushNode(next) {
+ {
+ next.context._currentValue2 = next.value;
+ }
+}
+
+function popToNearestCommonAncestor(prev, next) {
+ if (prev === next) ; else {
+ popNode(prev);
+ const parentPrev = prev.parent;
+ const parentNext = next.parent;
+
+ if (parentPrev === null) {
+ if (parentNext !== null) {
+ throw Error(formatProdErrorMessage(401));
+ }
+ } else {
+ if (parentNext === null) {
+ throw Error(formatProdErrorMessage(401));
+ }
+
+ popToNearestCommonAncestor(parentPrev, parentNext);
+ } // On the way back, we push the new ones that weren't common.
+
+
+ pushNode(next);
+ }
+}
+
+function popAllPrevious(prev) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev !== null) {
+ popAllPrevious(parentPrev);
+ }
+}
+
+function pushAllNext(next) {
+ const parentNext = next.parent;
+
+ if (parentNext !== null) {
+ pushAllNext(parentNext);
+ }
+
+ pushNode(next);
+}
+
+function popPreviousToCommonLevel(prev, next) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev === null) {
+ throw Error(formatProdErrorMessage(402));
+ }
+
+ if (parentPrev.depth === next.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(parentPrev, next);
+ } else {
+ // We must still be deeper.
+ popPreviousToCommonLevel(parentPrev, next);
+ }
+}
+
+function popNextToCommonLevel(prev, next) {
+ const parentNext = next.parent;
+
+ if (parentNext === null) {
+ throw Error(formatProdErrorMessage(402));
+ }
+
+ if (prev.depth === parentNext.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(prev, parentNext);
+ } else {
+ // We must still be deeper.
+ popNextToCommonLevel(prev, parentNext);
+ }
+
+ pushNode(next);
+} // Perform context switching to the new snapshot.
+// To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
+// updating all the context's current values. That way reads, always just read the current value.
+// At the cost of updating contexts even if they're never read by this subtree.
+
+
+function switchContext(newSnapshot) {
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
+ // We also need to update any new contexts that are now on the stack with the deepest value.
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
+ // for that. Therefore this algorithm is recursive.
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
+ // 3) Then we reapply new contexts on the way back up the stack.
+ const prev = currentActiveSnapshot;
+ const next = newSnapshot;
+
+ if (prev !== next) {
+ if (prev === null) {
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
+ pushAllNext(next);
+ } else if (next === null) {
+ popAllPrevious(prev);
+ } else if (prev.depth === next.depth) {
+ popToNearestCommonAncestor(prev, next);
+ } else if (prev.depth > next.depth) {
+ popPreviousToCommonLevel(prev, next);
+ } else {
+ popNextToCommonLevel(prev, next);
+ }
+
+ currentActiveSnapshot = next;
+ }
+}
+function pushProvider(context, nextValue) {
+ let prevValue;
+
+ {
+ prevValue = context._currentValue2;
+ context._currentValue2 = nextValue;
+ }
+
+ const prevNode = currentActiveSnapshot;
+ const newNode = {
+ parent: prevNode,
+ depth: prevNode === null ? 0 : prevNode.depth + 1,
+ context: context,
+ parentValue: prevValue,
+ value: nextValue
+ };
+ currentActiveSnapshot = newNode;
+ return newNode;
+}
+function popProvider(context) {
+ const prevSnapshot = currentActiveSnapshot;
+
+ if (prevSnapshot === null) {
+ throw Error(formatProdErrorMessage(403));
+ }
+
+ {
+ const value = prevSnapshot.parentValue;
+
+ if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) {
+ prevSnapshot.context._currentValue2 = prevSnapshot.context._defaultValue;
+ } else {
+ prevSnapshot.context._currentValue2 = value;
+ }
+ }
+
+ return currentActiveSnapshot = prevSnapshot.parent;
+}
+function getActiveContext() {
+ return currentActiveSnapshot;
+}
+function readContext$1(context) {
+ const value = context._currentValue2;
+ return value;
+}
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ *
+ * Note that this module is currently shared and assumed to be stateless.
+ * If this becomes an actual Map, that will break.
+ */
+function get(key) {
+ return key._reactInternals;
+}
+function set(key, value) {
+ key._reactInternals = value;
+}
+
+const classComponentUpdater = {
+ isMounted(inst) {
+ return false;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueSetState(inst, payload, callback) {
+ const internals = get(inst);
+
+ if (internals.queue === null) ; else {
+ internals.queue.push(payload);
+ }
+ },
+
+ enqueueReplaceState(inst, payload, callback) {
+ const internals = get(inst);
+ internals.replace = true;
+ internals.queue = [payload];
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueForceUpdate(inst, callback) {
+ }
+
+};
+
+function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) {
+ const partialState = getDerivedStateFromProps(nextProps, prevState);
+
+
+ const newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);
+ return newState;
+}
+
+function constructClassInstance(ctor, props, maskedLegacyContext) {
+ let context = emptyContextObject;
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ context = readContext$1(contextType);
+ } else {
+ context = maskedLegacyContext;
+ }
+
+ const instance = new ctor(props, context);
+
+ return instance;
+}
+
+function callComponentWillMount(type, instance) {
+ const oldState = instance.state;
+
+ if (typeof instance.componentWillMount === 'function') {
+
+ instance.componentWillMount();
+ }
+
+ if (typeof instance.UNSAFE_componentWillMount === 'function') {
+ instance.UNSAFE_componentWillMount();
+ }
+
+ if (oldState !== instance.state) {
+
+ classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
+ }
+}
+
+function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) {
+ if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
+ const oldQueue = internalInstance.queue;
+ const oldReplace = internalInstance.replace;
+ internalInstance.queue = null;
+ internalInstance.replace = false;
+
+ if (oldReplace && oldQueue.length === 1) {
+ inst.state = oldQueue[0];
+ } else {
+ let nextState = oldReplace ? oldQueue[0] : inst.state;
+ let dontMutate = true;
+
+ for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
+ const partial = oldQueue[i];
+ const partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial;
+
+ if (partialState != null) {
+ if (dontMutate) {
+ dontMutate = false;
+ nextState = assign({}, nextState, partialState);
+ } else {
+ assign(nextState, partialState);
+ }
+ }
+ }
+
+ inst.state = nextState;
+ }
+ } else {
+ internalInstance.queue = null;
+ }
+} // Invokes the mount life-cycles on a previously never rendered instance.
+
+
+function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) {
+
+ const initialState = instance.state !== undefined ? instance.state : null;
+ instance.updater = classComponentUpdater;
+ instance.props = newProps;
+ instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway.
+ // The internal instance will be used to manage updates that happen during this mount.
+
+ const internalInstance = {
+ queue: [],
+ replace: false
+ };
+ set(instance, internalInstance);
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ instance.context = readContext$1(contextType);
+ } else {
+ instance.context = maskedLegacyContext;
+ }
+
+ const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
+
+ if (typeof getDerivedStateFromProps === 'function') {
+ instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps);
+ } // In order to support react-lifecycles-compat polyfilled components,
+ // Unsafe lifecycles should not be invoked for components using the new APIs.
+
+
+ if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
+ callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's
+ // process them now.
+
+ processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext);
+ }
+}
+
+// Ids are base 32 strings whose binary representation corresponds to the
+// position of a node in a tree.
+// Every time the tree forks into multiple children, we add additional bits to
+// the left of the sequence that represent the position of the child within the
+// current level of children.
+//
+// 00101 00010001011010101
+// ╰─┬─╯ ╰───────┬───────╯
+// Fork 5 of 20 Parent id
+//
+// The leading 0s are important. In the above example, you only need 3 bits to
+// represent slot 5. However, you need 5 bits to represent all the forks at
+// the current level, so we must account for the empty bits at the end.
+//
+// For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise,
+// the zeroth id at a level would be indistinguishable from its parent.
+//
+// If a node has only one child, and does not materialize an id (i.e. does not
+// contain a useId hook), then we don't need to allocate any space in the
+// sequence. It's treated as a transparent indirection. For example, these two
+// trees produce the same ids:
+//
+// <> <>
+//
+//
+// >
+//
+// >
+//
+// However, we cannot skip any node that materializes an id. Otherwise, a parent
+// id that does not fork would be indistinguishable from its child id. For
+// example, this tree does not fork, but the parent and child must have
+// different ids.
+//
+//
+//
+//
+//
+// To handle this scenario, every time we materialize an id, we allocate a
+// new level with a single slot. You can think of this as a fork with only one
+// prong, or an array of children with length 1.
+//
+// It's possible for the size of the sequence to exceed 32 bits, the max
+// size for bitwise operations. When this happens, we make more room by
+// converting the right part of the id to a string and storing it in an overflow
+// variable. We use a base 32 string representation, because 32 is the largest
+// power of 2 that is supported by toString(). We want the base to be large so
+// that the resulting ids are compact, and we want the base to be a power of 2
+// because every log2(base) bits corresponds to a single character, i.e. every
+// log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without
+// affecting the final result.
+const emptyTreeContext = {
+ id: 1,
+ overflow: ''
+};
+function getTreeId(context) {
+ const overflow = context.overflow;
+ const idWithLeadingBit = context.id;
+ const id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);
+ return id.toString(32) + overflow;
+}
+function pushTreeContext(baseContext, totalChildren, index) {
+ const baseIdWithLeadingBit = baseContext.id;
+ const baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part
+ // of the id; we use it to account for leading 0s.
+
+ const baseLength = getBitLength(baseIdWithLeadingBit) - 1;
+ const baseId = baseIdWithLeadingBit & ~(1 << baseLength);
+ const slot = index + 1;
+ const length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into
+ // consideration the leading 1 we use to mark the end of the sequence.
+
+ if (length > 30) {
+ // We overflowed the bitwise-safe range. Fall back to slower algorithm.
+ // This branch assumes the length of the base id is greater than 5; it won't
+ // work for smaller ids, because you need 5 bits per character.
+ //
+ // We encode the id in multiple steps: first the base id, then the
+ // remaining digits.
+ //
+ // Each 5 bit sequence corresponds to a single base 32 character. So for
+ // example, if the current id is 23 bits long, we can convert 20 of those
+ // bits into a string of 4 characters, with 3 bits left over.
+ //
+ // First calculate how many bits in the base id represent a complete
+ // sequence of characters.
+ const numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.
+
+ const newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.
+
+ const newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.
+
+ const restOfBaseId = baseId >> numberOfOverflowBits;
+ const restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because
+ // we made more room, this time it won't overflow.
+
+ const restOfLength = getBitLength(totalChildren) + restOfBaseLength;
+ const restOfNewBits = slot << restOfBaseLength;
+ const id = restOfNewBits | restOfBaseId;
+ const overflow = newOverflow + baseOverflow;
+ return {
+ id: 1 << restOfLength | id,
+ overflow
+ };
+ } else {
+ // Normal path
+ const newBits = slot << baseLength;
+ const id = newBits | baseId;
+ const overflow = baseOverflow;
+ return {
+ id: 1 << length | id,
+ overflow
+ };
+ }
+}
+
+function getBitLength(number) {
+ return 32 - clz32(number);
+}
+
+function getLeadingBit(id) {
+ return 1 << getBitLength(id) - 1;
+} // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback.
+
+
+const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.
+// Based on:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+const log = Math.log;
+const LN2 = Math.LN2;
+
+function clz32Fallback(x) {
+ const asUint = x >>> 0;
+
+ if (asUint === 0) {
+ return 32;
+ }
+
+ return 31 - (log(asUint) / LN2 | 0) | 0;
+}
+
+// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
+// changes to one module should be reflected in the others.
+// TODO: Rename this module and the corresponding Fiber one to "Thenable"
+// instead of "Wakeable". Or some other more appropriate name.
+// An error that is thrown (e.g. by `use`) to trigger Suspense. If we
+// detect this is caught by userspace, we'll log a warning in development.
+const SuspenseException = Error(formatProdErrorMessage(460));
+function createThenableState() {
+ // The ThenableState is created the first time a component suspends. If it
+ // suspends again, we'll reuse the same state.
+ return [];
+}
+
+function noop$2() {}
+
+function trackUsedThenable(thenableState, thenable, index) {
+ const previous = thenableState[index];
+
+ if (previous === undefined) {
+ thenableState.push(thenable);
+ } else {
+ if (previous !== thenable) {
+ // Reuse the previous thenable, and drop the new one. We can assume
+ // they represent the same value, because components are idempotent.
+ // Avoid an unhandled rejection errors for the Promises that we'll
+ // intentionally ignore.
+ thenable.then(noop$2, noop$2);
+ thenable = previous;
+ }
+ } // We use an expando to track the status and result of a thenable so that we
+ // can synchronously unwrap the value. Think of this as an extension of the
+ // Promise API, or a custom interface that is a superset of Thenable.
+ //
+ // If the thenable doesn't have a status, set it to "pending" and attach
+ // a listener that will update its status and result when it resolves.
+
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledValue = thenable.value;
+ return fulfilledValue;
+ }
+
+ case 'rejected':
+ {
+ const rejectedError = thenable.reason;
+ throw rejectedError;
+ }
+
+ default:
+ {
+ if (typeof thenable.status === 'string') ; else {
+ const pendingThenable = thenable;
+ pendingThenable.status = 'pending';
+ pendingThenable.then(fulfilledValue => {
+ if (thenable.status === 'pending') {
+ const fulfilledThenable = thenable;
+ fulfilledThenable.status = 'fulfilled';
+ fulfilledThenable.value = fulfilledValue;
+ }
+ }, error => {
+ if (thenable.status === 'pending') {
+ const rejectedThenable = thenable;
+ rejectedThenable.status = 'rejected';
+ rejectedThenable.reason = error;
+ }
+ }); // Check one more time in case the thenable resolved synchronously
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledThenable = thenable;
+ return fulfilledThenable.value;
+ }
+
+ case 'rejected':
+ {
+ const rejectedThenable = thenable;
+ throw rejectedThenable.reason;
+ }
+ }
+ } // Suspend.
+ //
+ // Throwing here is an implementation detail that allows us to unwind the
+ // call stack. But we shouldn't allow it to leak into userspace. Throw an
+ // opaque placeholder value instead of the actual thenable. If it doesn't
+ // get captured by the work loop, log a warning, because that means
+ // something in userspace must have caught it.
+
+
+ suspendedThenable = thenable;
+ throw SuspenseException;
+ }
+ }
+} // This is used to track the actual thenable that suspended so it can be
+// passed to the rest of the Suspense implementation — which, for historical
+// reasons, expects to receive a thenable.
+
+let suspendedThenable = null;
+function getSuspendedThenable() {
+ // This is called right after `use` suspends by throwing an exception. `use`
+ // throws an opaque value instead of the thenable itself so that it can't be
+ // caught in userspace. Then the work loop accesses the actual thenable using
+ // this function.
+ if (suspendedThenable === null) {
+ throw Error(formatProdErrorMessage(459));
+ }
+
+ const thenable = suspendedThenable;
+ suspendedThenable = null;
+ return thenable;
+}
+
+/**
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+ */
+function is(x, y) {
+ return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
+ ;
+}
+
+const objectIs = // $FlowFixMe[method-unbinding]
+typeof Object.is === 'function' ? Object.is : is;
+
+let currentlyRenderingComponent = null;
+let currentlyRenderingTask = null;
+let currentlyRenderingRequest = null;
+let currentlyRenderingKeyPath = null;
+let firstWorkInProgressHook = null;
+let workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook
+
+let isReRender = false; // Whether an update was scheduled during the currently executing render pass.
+
+let didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component
+
+let localIdCounter = 0; // Chunks that should be pushed to the stream once the component
+// finishes rendering.
+// Counts the number of useFormState calls in this component
+
+let formStateCounter = 0; // The index of the useFormState hook that matches the one passed in at the
+// root during an MPA navigation, if any.
+
+let formStateMatchingIndex = -1; // Counts the number of use(thenable) calls in this component
+
+let thenableIndexCounter = 0;
+let thenableState = null; // Lazily created map of render-phase updates
+
+let renderPhaseUpdates = null; // Counter to prevent infinite loops.
+
+let numberOfReRenders = 0;
+const RE_RENDER_LIMIT = 25;
+
+function resolveCurrentlyRenderingComponent() {
+ if (currentlyRenderingComponent === null) {
+ throw Error(formatProdErrorMessage(321));
+ }
+
+ return currentlyRenderingComponent;
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+
+ return false;
+ }
+
+
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ if (objectIs(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+function createHook() {
+ if (numberOfReRenders > 0) {
+ throw Error(formatProdErrorMessage(312));
+ }
+
+ return {
+ memoizedState: null,
+ queue: null,
+ next: null
+ };
+}
+
+function createWorkInProgressHook() {
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ if (firstWorkInProgressHook === null) {
+ isReRender = false;
+ firstWorkInProgressHook = workInProgressHook = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = firstWorkInProgressHook;
+ }
+ } else {
+ if (workInProgressHook.next === null) {
+ isReRender = false; // Append to the end of the list
+
+ workInProgressHook = workInProgressHook.next = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = workInProgressHook.next;
+ }
+ }
+
+ return workInProgressHook;
+}
+
+function prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState) {
+ currentlyRenderingComponent = componentIdentity;
+ currentlyRenderingTask = task;
+ currentlyRenderingRequest = request;
+ currentlyRenderingKeyPath = keyPath;
+ // didScheduleRenderPhaseUpdate = false;
+ // firstWorkInProgressHook = null;
+ // numberOfReRenders = 0;
+ // renderPhaseUpdates = null;
+ // workInProgressHook = null;
+
+
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ thenableState = prevThenableState;
+}
+function finishHooks(Component, props, children, refOrContext) {
+ // This must be called after every function component to prevent hooks from
+ // being used in classes.
+ while (didScheduleRenderPhaseUpdate) {
+ // Updates were scheduled during the render phase. They are stored in
+ // the `renderPhaseUpdates` map. Call the component again, reusing the
+ // work-in-progress hooks and applying the additional updates on top. Keep
+ // restarting until no more updates are scheduled.
+ didScheduleRenderPhaseUpdate = false;
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ numberOfReRenders += 1; // Start over from the beginning of the list
+
+ workInProgressHook = null;
+ children = Component(props, refOrContext);
+ }
+
+ resetHooksState();
+ return children;
+}
+function getThenableStateAfterSuspending() {
+ const state = thenableState;
+ thenableState = null;
+ return state;
+}
+function checkDidRenderIdHook() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ const didRenderIdHook = localIdCounter !== 0;
+ return didRenderIdHook;
+}
+function getFormStateCount() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateCounter;
+}
+function getFormStateMatchingIndex() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateMatchingIndex;
+} // Reset the internal hooks state if an error occurs while rendering a component
+
+function resetHooksState() {
+
+ currentlyRenderingComponent = null;
+ currentlyRenderingTask = null;
+ currentlyRenderingRequest = null;
+ currentlyRenderingKeyPath = null;
+ didScheduleRenderPhaseUpdate = false;
+ firstWorkInProgressHook = null;
+ numberOfReRenders = 0;
+ renderPhaseUpdates = null;
+ workInProgressHook = null;
+}
+
+function readContext(context) {
+
+ return readContext$1(context);
+}
+
+function useContext(context) {
+
+ resolveCurrentlyRenderingComponent();
+ return readContext$1(context);
+}
+
+function basicStateReducer(state, action) {
+ // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
+ return typeof action === 'function' ? action(state) : action;
+}
+
+function useState(initialState) {
+
+ return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers
+ initialState);
+}
+function useReducer(reducer, initialArg, init) {
+
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+
+ if (isReRender) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ // current hook.
+ const queue = workInProgressHook.queue;
+ const dispatch = queue.dispatch;
+
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate !== undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.delete(queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ let newState = workInProgressHook.memoizedState;
+ let update = firstRenderPhaseUpdate;
+
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ const action = update.action;
+
+ newState = reducer(newState, action);
+
+
+ update = update.next;
+ } while (update !== null); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ workInProgressHook.memoizedState = newState;
+ return [newState, dispatch];
+ }
+ } // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ return [workInProgressHook.memoizedState, dispatch];
+ } else {
+
+ let initialState;
+
+ if (reducer === basicStateReducer) {
+ // Special case for `useState`.
+ initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
+ } else {
+ initialState = init !== undefined ? init(initialArg) : initialArg;
+ }
+
+
+ workInProgressHook.memoizedState = initialState; // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ const queue = workInProgressHook.queue = {
+ last: null,
+ dispatch: null
+ };
+ const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ return [workInProgressHook.memoizedState, dispatch];
+ }
+}
+
+function useMemo(nextCreate, deps) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const nextDeps = deps === undefined ? null : deps;
+
+ if (workInProgressHook !== null) {
+ const prevState = workInProgressHook.memoizedState;
+
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ const prevDeps = prevState[1];
+
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ }
+
+ const nextValue = nextCreate();
+
+
+ workInProgressHook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function useRef(initialValue) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const previousRef = workInProgressHook.memoizedState;
+
+ if (previousRef === null) {
+ const ref = {
+ current: initialValue
+ };
+
+
+ workInProgressHook.memoizedState = ref;
+ return ref;
+ } else {
+ return previousRef;
+ }
+}
+
+function dispatchAction(componentIdentity, queue, action) {
+ if (numberOfReRenders >= RE_RENDER_LIMIT) {
+ throw Error(formatProdErrorMessage(301));
+ }
+
+ if (componentIdentity === currentlyRenderingComponent) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ const update = {
+ action,
+ next: null
+ };
+
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate === undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+
+ lastRenderPhaseUpdate.next = update;
+ }
+ }
+}
+
+function useCallback(callback, deps) {
+ return useMemo(() => callback, deps);
+}
+
+function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
+ if (getServerSnapshot === undefined) {
+ throw Error(formatProdErrorMessage(407));
+ }
+
+ return getServerSnapshot();
+}
+
+function useDeferredValue(value, initialValue) {
+ resolveCurrentlyRenderingComponent();
+
+ {
+ return value;
+ }
+}
+
+function unsupportedStartTransition() {
+ throw Error(formatProdErrorMessage(394));
+}
+
+function useTransition() {
+ resolveCurrentlyRenderingComponent();
+ return [false, unsupportedStartTransition];
+}
+
+function useHostTransitionStatus() {
+ resolveCurrentlyRenderingComponent();
+ return NotPendingTransition;
+}
+
+function unsupportedSetOptimisticState() {
+ throw Error(formatProdErrorMessage(479));
+}
+
+function useOptimistic(passthrough, reducer) {
+ resolveCurrentlyRenderingComponent();
+ return [passthrough, unsupportedSetOptimisticState];
+}
+
+function createPostbackFormStateKey(permalink, componentKeyPath, hookIndex) {
+ if (permalink !== undefined) {
+ // Don't bother to hash a permalink-based key since it's already short.
+ return 'p' + permalink;
+ } else {
+ // Append a node to the key path that represents the form state hook.
+ const keyPath = [componentKeyPath, null, hookIndex]; // Key paths are hashed to reduce the size. It does not need to be secure,
+ // and it's more important that it's fast than that it's completely
+ // collision-free.
+
+ const keyPathHash = createFastHashJS(JSON.stringify(keyPath));
+ return 'k' + keyPathHash;
+ }
+}
+
+function useFormState(action, initialState, permalink) {
+ resolveCurrentlyRenderingComponent(); // Count the number of useFormState hooks per component. We also use this to
+ // track the position of this useFormState hook relative to the other ones in
+ // this component, so we can generate a unique key for each one.
+
+ const formStateHookIndex = formStateCounter++;
+ const request = currentlyRenderingRequest; // $FlowIgnore[prop-missing]
+
+ const formAction = action.$$FORM_ACTION;
+
+ if (typeof formAction === 'function') {
+ // This is a server action. These have additional features to enable
+ // MPA-style form submissions with progressive enhancement.
+ // TODO: If the same permalink is passed to multiple useFormStates, and
+ // they all have the same action signature, Fizz will pass the postback
+ // state to all of them. We should probably only pass it to the first one,
+ // and/or warn.
+ // The key is lazily generated and deduped so the that the keypath doesn't
+ // get JSON.stringify-ed unnecessarily, and at most once.
+ let nextPostbackStateKey = null; // Determine the current form state. If we received state during an MPA form
+ // submission, then we will reuse that, if the action identity matches.
+ // Otherwise we'll use the initial state argument. We will emit a comment
+ // marker into the stream that indicates whether the state was reused.
+
+ let state = initialState;
+ const componentKeyPath = currentlyRenderingKeyPath;
+ const postbackFormState = getFormState(request); // $FlowIgnore[prop-missing]
+
+ const isSignatureEqual = action.$$IS_SIGNATURE_EQUAL;
+
+ if (postbackFormState !== null && typeof isSignatureEqual === 'function') {
+ const postbackKey = postbackFormState[1];
+ const postbackReferenceId = postbackFormState[2];
+ const postbackBoundArity = postbackFormState[3];
+
+ if (isSignatureEqual.call(action, postbackReferenceId, postbackBoundArity)) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+
+ if (postbackKey === nextPostbackStateKey) {
+ // This was a match
+ formStateMatchingIndex = formStateHookIndex; // Reuse the state that was submitted by the form.
+
+ state = postbackFormState[0];
+ }
+ }
+ } // Bind the state to the first argument of the action.
+
+
+ const boundAction = action.bind(null, state); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ }; // $FlowIgnore[prop-missing]
+
+
+ if (typeof boundAction.$$FORM_ACTION === 'function') {
+ // $FlowIgnore[prop-missing]
+ dispatch.$$FORM_ACTION = prefix => {
+ const metadata = boundAction.$$FORM_ACTION(prefix); // Override the action URL
+
+ if (permalink !== undefined) {
+
+ permalink += '';
+ metadata.action = permalink;
+ }
+
+ const formData = metadata.data;
+
+ if (formData) {
+ if (nextPostbackStateKey === null) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+ }
+
+ formData.append('$ACTION_KEY', nextPostbackStateKey);
+ }
+
+ return metadata;
+ };
+ }
+
+ return [state, dispatch];
+ } else {
+ // This is not a server action, so the implementation is much simpler.
+ // Bind the state to the first argument of the action.
+ const boundAction = action.bind(null, initialState); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ };
+
+ return [initialState, dispatch];
+ }
+}
+
+function useId() {
+ const task = currentlyRenderingTask;
+ const treeId = getTreeId(task.treeContext);
+ const resumableState = currentResumableState;
+
+ if (resumableState === null) {
+ throw Error(formatProdErrorMessage(404));
+ }
+
+ const localId = localIdCounter++;
+ return makeId(resumableState, treeId, localId);
+}
+
+function use(usable) {
+ if (usable !== null && typeof usable === 'object') {
+ // $FlowFixMe[method-unbinding]
+ if (typeof usable.then === 'function') {
+ // This is a thenable.
+ const thenable = usable;
+ return unwrapThenable(thenable);
+ } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = usable;
+ return readContext(context);
+ }
+ } // eslint-disable-next-line react-internal/safe-string-coercion
+
+
+ throw Error(formatProdErrorMessage(438, String(usable)));
+}
+
+function unwrapThenable(thenable) {
+ const index = thenableIndexCounter;
+ thenableIndexCounter += 1;
+
+ if (thenableState === null) {
+ thenableState = createThenableState();
+ }
+
+ return trackUsedThenable(thenableState, thenable, index);
+}
+
+function unsupportedRefresh() {
+ throw Error(formatProdErrorMessage(393));
+}
+
+function useCacheRefresh() {
+ return unsupportedRefresh;
+}
+
+function noop$1() {}
+
+const HooksDispatcher = {
+ readContext,
+ use,
+ useContext,
+ useMemo,
+ useReducer,
+ useRef,
+ useState,
+ useInsertionEffect: noop$1,
+ useLayoutEffect: noop$1,
+ useCallback,
+ // useImperativeHandle is not run in the server environment
+ useImperativeHandle: noop$1,
+ // Effects are not run in the server environment.
+ useEffect: noop$1,
+ // Debugging effect
+ useDebugValue: noop$1,
+ useDeferredValue,
+ useTransition,
+ useId,
+ // Subscriptions are not setup in a server environment.
+ useSyncExternalStore
+};
+
+{
+ HooksDispatcher.useCacheRefresh = useCacheRefresh;
+}
+
+{
+ HooksDispatcher.useHostTransitionStatus = useHostTransitionStatus;
+}
+
+{
+ HooksDispatcher.useOptimistic = useOptimistic;
+ HooksDispatcher.useFormState = useFormState;
+}
+
+let currentResumableState = null;
+function setCurrentResumableState(resumableState) {
+ currentResumableState = resumableState;
+}
+
+function getCacheSignal() {
+ throw Error(formatProdErrorMessage(248));
+}
+
+function getCacheForType(resourceType) {
+ throw Error(formatProdErrorMessage(248));
+}
+
+const DefaultCacheDispatcher = {
+ getCacheSignal,
+ getCacheForType
+};
+
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
+const ReactCurrentCache = ReactSharedInternals.ReactCurrentCache;
+// The name might be minified but we assume that it's going to be the same generated name. Typically
+// because it's just the same compiled output in practice.
+// resume with segmentID at the index
+
+const CLIENT_RENDERED = 4; // if it errors or infinitely suspends
+
+const PENDING = 0;
+const COMPLETED = 1;
+const FLUSHED = 2;
+const ABORTED = 3;
+const ERRORED = 4;
+const POSTPONED = 5;
+const OPEN = 0;
+const CLOSING = 1;
+const CLOSED = 2; // This is a default heuristic for how to split up the HTML content into progressive
+// loading. Our goal is to be able to display additional new content about every 500ms.
+// Faster than that is unnecessary and should be throttled on the client. It also
+// adds unnecessary overhead to do more splits. We don't know if it's a higher or lower
+// end device but higher end suffer less from the overhead than lower end does from
+// not getting small enough pieces. We error on the side of low end.
+// We base this on low end 3G speeds which is about 500kbits per second. We assume
+// that there can be a reasonable drop off from max bandwidth which leaves you with
+// as little as 80%. We can receive half of that each 500ms - at best. In practice,
+// a little bandwidth is lost to processing and contention - e.g. CSS and images that
+// are downloaded along with the main content. So we estimate about half of that to be
+// the lower end throughput. In other words, we expect that you can at least show
+// about 12.5kb of content per 500ms. Not counting starting latency for the first
+// paint.
+// 500 * 1024 / 8 * .8 * 0.5 / 2
+
+const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
+
+function defaultErrorHandler(error) {
+ console['error'](error); // Don't transform to our wrapper
+
+ return null;
+}
+
+function noop() {}
+
+function createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, formState) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState,
+ renderState,
+ rootFormatContext,
+ progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: 0,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: formState === undefined ? null : formState
+ }; // This segment represents the root fallback.
+
+ const rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false); // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+let currentRequest = null;
+function resolveRequest() {
+ if (currentRequest) return currentRequest;
+
+ return null;
+}
+
+function pingTask(request, task) {
+ const pingedTasks = request.pingedTasks;
+ pingedTasks.push(task);
+
+ if (request.pingedTasks.length === 1) {
+ request.flushScheduled = request.destination !== null;
+ scheduleWork(() => performWork(request));
+ }
+}
+
+function createSuspenseBoundary(request, fallbackAbortableTasks) {
+ return {
+ status: PENDING,
+ rootSegmentID: -1,
+ parentFlushed: false,
+ pendingTasks: 0,
+ completedSegments: [],
+ byteSize: 0,
+ fallbackAbortableTasks,
+ errorDigest: null,
+ resources: createBoundaryResources(),
+ trackedContentKeyPath: null,
+ trackedFallbackNode: null
+ };
+}
+
+function createRenderTask(request, thenableState, node, childIndex, blockedBoundary, blockedSegment, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ const task = {
+ replay: null,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createReplayTask(request, thenableState, replay, node, childIndex, blockedBoundary, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ replay.pendingTasks++;
+ const task = {
+ replay,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment: null,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createPendingSegment(request, index, boundary, parentFormatContext, lastPushedText, textEmbedded) {
+ return {
+ status: PENDING,
+ id: -1,
+ // lazily assigned later
+ index,
+ parentFlushed: false,
+ chunks: [],
+ children: [],
+ parentFormatContext,
+ boundary,
+ lastPushedText,
+ textEmbedded
+ };
+} // DEV-only global reference to the currently executing task
+
+function popComponentStackInDEV(task) {
+} // stash the component stack of an unwinding error until it is processed
+
+function logRecoverableError(request, error) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ const errorDigest = request.onError(error);
+
+ if (errorDigest != null && typeof errorDigest !== 'string') {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead");
+ }
+
+ return errorDigest;
+}
+
+function fatalError(request, error) {
+ // This is called outside error handling code such as if the root errors outside
+ // a suspense boundary or if the root suspense boundary's fallback errors.
+ // It's also called if React itself or its host configs errors.
+ const onShellError = request.onShellError;
+ onShellError(error);
+ const onFatalError = request.onFatalError;
+ onFatalError(error);
+
+ if (request.destination !== null) {
+ request.status = CLOSED;
+ closeWithError(request.destination, error);
+ } else {
+ request.status = CLOSING;
+ request.fatalError = error;
+ }
+}
+
+function renderSuspenseBoundary(request, someTask, keyPath, props) {
+ if (someTask.replay !== null) {
+ // If we're replaying through this pass, it means we're replaying through
+ // an already completed Suspense boundary. It's too late to do anything about it
+ // so we can just render through it.
+ const prevKeyPath = someTask.keyPath;
+ someTask.keyPath = keyPath;
+ const content = props.children;
+
+ try {
+ renderNode(request, someTask, content, -1);
+ } finally {
+ someTask.keyPath = prevKeyPath;
+ }
+
+ return;
+ } // $FlowFixMe: Refined.
+
+
+ const task = someTask;
+ const prevKeyPath = task.keyPath;
+ const parentBoundary = task.blockedBoundary;
+ const parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for
+ // the fallback so that we can later replace that segment with the content.
+ // This also lets us split out the main content even if it doesn't suspend,
+ // in case it ends up generating a large subtree of content.
+
+ const fallback = props.fallback;
+ const content = props.children;
+ const fallbackAbortSet = new Set();
+ const newBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+
+ if (request.trackedPostpones !== null) {
+ newBoundary.trackedContentKeyPath = keyPath;
+ }
+
+ const insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback.
+
+ const boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false);
+ parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent
+
+ parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately.
+
+ const contentRootSegment = createPendingSegment(request, 0, null, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is
+ // no parent segment so there's nothing to wait on.
+
+ contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks.
+ // I suspect that there might be some efficiency benefits from not creating the suspended task
+ // and instead just using the stack if possible.
+ // TODO: Call this directly instead of messing with saving and restoring contexts.
+ // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and which segment
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = newBoundary;
+ task.blockedSegment = contentRootSegment;
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, newBoundary.resources);
+ }
+
+ task.keyPath = keyPath;
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+ pushSegmentFinale(contentRootSegment.chunks, request.renderState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded);
+ contentRootSegment.status = COMPLETED;
+ queueCompletedSegment(newBoundary, contentRootSegment);
+
+ if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
+ newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ contentRootSegment.status = ERRORED;
+ newBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ newBoundary.errorDigest = errorDigest;
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.blockedSegment = parentSegment;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]];
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones !== null) {
+ // We create a detached replay node to track any postpones inside the fallback.
+ const fallbackReplayNode = [fallbackKeyPath[1], fallbackKeyPath[2], [], null];
+ trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
+
+ if (newBoundary.status === POSTPONED) {
+ // This must exist now.
+ const boundaryReplayNode = trackedPostpones.workingMap.get(keyPath);
+ boundaryReplayNode[4] = fallbackReplayNode;
+ } else {
+ // We might not inject it into the postponed tree, unless the content actually
+ // postpones too. We need to keep track of it until that happpens.
+ newBoundary.trackedFallbackNode = fallbackReplayNode;
+ }
+ } // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+
+ const suspendedFallbackTask = createRenderTask(request, null, fallback, -1, parentBoundary, boundarySegment, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function replaySuspenseBoundary(request, task, keyPath, props, id, childNodes, childSlots, fallbackNodes, fallbackSlots) {
+ const prevKeyPath = task.keyPath;
+ const previousReplaySet = task.replay;
+ const parentBoundary = task.blockedBoundary;
+ const content = props.children;
+ const fallback = props.fallback;
+ const fallbackAbortSet = new Set();
+ const resumedBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = id; // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and replay node
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = resumedBoundary;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, resumedBoundary.resources);
+ }
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+
+ if (resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING) {
+ resumedBoundary.status = COMPLETED;
+ request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ resumedBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ resumedBoundary.errorDigest = errorDigest;
+
+ task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted.
+
+ request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task.
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.replay = previousReplaySet;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+ const fallbackReplay = {
+ nodes: fallbackNodes,
+ slots: fallbackSlots,
+ pendingTasks: 0
+ };
+ const suspendedFallbackTask = createReplayTask(request, null, fallbackReplay, fallback, -1, parentBoundary, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function renderHostElement(request, task, keyPath, type, props) {
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ const children = props.children; // TODO: Make this a Config for replaying.
+
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ } else {
+ // Render
+ const children = pushStartInstance(segment.chunks, type, props, request.resumableState, request.renderState, task.formatContext, segment.lastPushedText);
+ segment.lastPushedText = false;
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ pushEndInstance(segment.chunks, type, props, request.resumableState, prevContext);
+ segment.lastPushedText = false;
+ }
+}
+
+function shouldConstruct(Component) {
+ return Component.prototype && Component.prototype.isReactComponent;
+}
+
+function renderWithHooks(request, task, keyPath, prevThenableState, Component, props, secondArg) {
+ const componentIdentity = {};
+ prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState);
+ const result = Component(props, secondArg);
+ return finishHooks(Component, props, result, secondArg);
+}
+
+function finishClassComponent(request, task, keyPath, instance, Component, props) {
+ const nextChildren = instance.render();
+
+ {
+ const childContextTypes = Component.childContextTypes;
+
+ if (childContextTypes !== null && childContextTypes !== undefined) {
+ const previousContext = task.legacyContext;
+ const mergedContext = processChildContext(instance, Component, previousContext, childContextTypes);
+ task.legacyContext = mergedContext;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.legacyContext = previousContext;
+ return;
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderClassComponent(request, task, keyPath, Component, props) {
+ const maskedContext = getMaskedContext(Component, task.legacyContext) ;
+ const instance = constructClassInstance(Component, props, maskedContext);
+ mountClassInstance(instance, Component, props, maskedContext);
+ finishClassComponent(request, task, keyPath, instance, Component);
+}
+// components for some reason.
+
+function renderIndeterminateComponent(request, task, keyPath, prevThenableState, Component, props) {
+ let legacyContext;
+
+ {
+ legacyContext = getMaskedContext(Component, task.legacyContext);
+ }
+
+ const value = renderWithHooks(request, task, keyPath, prevThenableState, Component, props, legacyContext);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+
+ if ( // Run these checks in production only if the flag is off.
+ // Eventually we'll delete this branch altogether.
+ typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
+
+ mountClassInstance(value, Component, props, legacyContext);
+ finishClassComponent(request, task, keyPath, value, Component);
+ } else {
+
+ finishFunctionComponent(request, task, keyPath, value, hasId, formStateCount, formStateMatchingIndex);
+ }
+}
+
+function finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex) {
+ let didEmitFormStateMarkers = false;
+
+ if (formStateCount !== 0 && request.formState !== null) {
+ // For each useFormState hook, emit a marker that indicates whether we
+ // rendered using the form state passed at the root. We only emit these
+ // markers if form state is passed at the root.
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ didEmitFormStateMarkers = true;
+ const target = segment.chunks;
+
+ for (let i = 0; i < formStateCount; i++) {
+ if (i === formStateMatchingIndex) {
+ pushFormStateMarkerIsMatching(target);
+ } else {
+ pushFormStateMarkerIsNotMatching(target);
+ }
+ }
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+
+ if (hasId) {
+ // This component materialized an id. We treat this as its own level, with
+ // a single "child" slot.
+ const prevTreeContext = task.treeContext;
+ const totalChildren = 1;
+ const index = 0; // Modify the id context. Because we'll need to reset this if something
+ // suspends or errors, we'll use the non-destructive render path.
+
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
+ renderNode(request, task, children, -1); // Like the other contexts, this does not need to be in a finally block
+ // because renderNode takes care of unwinding the stack.
+
+ task.treeContext = prevTreeContext;
+ } else if (didEmitFormStateMarkers) {
+ // If there were formState hooks, we must use the non-destructive path
+ // because this component is not a pure indirection; we emitted markers
+ // to the stream.
+ renderNode(request, task, children, -1);
+ } else {
+ // We're now successfully past this task, and we haven't modified the
+ // context stack. We don't have to pop back to the previous task every
+ // again, so we can use the destructive recursive form.
+ renderNodeDestructive(request, task, null, children, -1);
+ }
+
+ task.keyPath = prevKeyPath;
+}
+
+function resolveDefaultProps(Component, baseProps) {
+ if (Component && Component.defaultProps) {
+ // Resolve default props. Taken from ReactElement
+ const props = assign({}, baseProps);
+ const defaultProps = Component.defaultProps;
+
+ for (const propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+
+ return props;
+ }
+
+ return baseProps;
+}
+
+function renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref) {
+ const children = renderWithHooks(request, task, keyPath, prevThenableState, type.render, props, ref);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+ finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex);
+}
+
+function renderMemo(request, task, keyPath, prevThenableState, type, props, ref) {
+ const innerType = type.type;
+ const resolvedProps = resolveDefaultProps(innerType, props);
+ renderElement(request, task, keyPath, prevThenableState, innerType, resolvedProps, ref);
+}
+
+function renderContextConsumer(request, task, keyPath, context, props) {
+
+ const render = props.children;
+
+ const newValue = readContext$1(context);
+ const newChildren = render(newValue);
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, newChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderContextProvider(request, task, keyPath, type, props) {
+ const context = type._context;
+ const value = props.value;
+ const children = props.children;
+
+ const prevKeyPath = task.keyPath;
+ task.context = pushProvider(context, value);
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, children, -1);
+ task.context = popProvider();
+ task.keyPath = prevKeyPath;
+}
+
+function renderLazyComponent(request, task, keyPath, prevThenableState, lazyComponent, props, ref) {
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+ const Component = init(payload);
+ const resolvedProps = resolveDefaultProps(Component, props);
+ renderElement(request, task, keyPath, prevThenableState, Component, resolvedProps, ref);
+}
+
+function renderOffscreen(request, task, keyPath, props) {
+ const mode = props.mode;
+
+ if (mode === 'hidden') ; else {
+ // A visible Offscreen boundary is treated exactly like a fragment: a
+ // pure indirection.
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ }
+}
+
+function renderElement(request, task, keyPath, prevThenableState, type, props, ref) {
+ if (typeof type === 'function') {
+ if (shouldConstruct(type)) {
+ renderClassComponent(request, task, keyPath, type, props);
+ return;
+ } else {
+ renderIndeterminateComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+
+ if (typeof type === 'string') {
+ renderHostElement(request, task, keyPath, type, props);
+ return;
+ }
+
+ switch (type) {
+ // LegacyHidden acts the same as a fragment. This only works because we
+ // currently assume that every instance of LegacyHidden is accompanied by a
+ // host component wrapper. In the hidden mode, the host component is given a
+ // `hidden` attribute, which ensures that the initial HTML is not visible.
+ // To support the use of LegacyHidden as a true fragment, without an extra
+ // DOM node, we would have to hide the initial HTML in some other way.
+ // TODO: Delete in LegacyHidden. It's an unstable API only used in the
+ // www build. As a migration step, we could add a special prop to Offscreen
+ // that simulates the old behavior (no hiding, no change to effects).
+ case REACT_LEGACY_HIDDEN_TYPE:
+ case REACT_DEBUG_TRACING_MODE_TYPE:
+ case REACT_STRICT_MODE_TYPE:
+ case REACT_PROFILER_TYPE:
+ case REACT_FRAGMENT_TYPE:
+ {
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_OFFSCREEN_TYPE:
+ {
+ renderOffscreen(request, task, keyPath, props);
+ return;
+ }
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ {
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_SCOPE_TYPE:
+ {
+
+ throw Error(formatProdErrorMessage(343));
+ }
+
+ case REACT_SUSPENSE_TYPE:
+ {
+ {
+ renderSuspenseBoundary(request, task, keyPath, props);
+ }
+
+ return;
+ }
+ }
+
+ if (typeof type === 'object' && type !== null) {
+ switch (type.$$typeof) {
+ case REACT_FORWARD_REF_TYPE:
+ {
+ renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_MEMO_TYPE:
+ {
+ renderMemo(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_PROVIDER_TYPE:
+ {
+ renderContextProvider(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_CONTEXT_TYPE:
+ {
+ renderContextConsumer(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_LAZY_TYPE:
+ {
+ renderLazyComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+ }
+
+ let info = '';
+
+ throw Error(formatProdErrorMessage(130, type == null ? type : typeof type, info));
+}
+
+function resumeNode(request, task, segmentId, node, childIndex) {
+ const prevReplay = task.replay;
+ const blockedBoundary = task.blockedBoundary;
+ const resumedSegment = createPendingSegment(request, 0, null, task.formatContext, false, false);
+ resumedSegment.id = segmentId;
+ resumedSegment.parentFlushed = true;
+
+ try {
+ // Convert the current ReplayTask to a RenderTask.
+ const renderTask = task;
+ renderTask.replay = null;
+ renderTask.blockedSegment = resumedSegment;
+ renderNode(request, task, node, childIndex);
+ resumedSegment.status = COMPLETED;
+
+ if (blockedBoundary === null) {
+ request.completedRootSegment = resumedSegment;
+ } else {
+ queueCompletedSegment(blockedBoundary, resumedSegment);
+
+ if (blockedBoundary.parentFlushed) {
+ request.partialBoundaries.push(blockedBoundary);
+ }
+ }
+ } finally {
+ // Restore to a ReplayTask.
+ task.replay = prevReplay;
+ task.blockedSegment = null;
+ }
+}
+
+function replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, replay) {
+ // We're replaying. Find the path to follow.
+ const replayNodes = replay.nodes;
+
+ for (let i = 0; i < replayNodes.length; i++) {
+ // Flow doesn't support refinement on tuples so we do it manually here.
+ const node = replayNodes[i];
+
+ if (keyOrIndex !== node[1]) {
+ continue;
+ }
+
+ if (node.length === 4) {
+ // Matched a replayable path.
+ // Let's double check that the component name matches as a precaution.
+ if (name !== null && name !== node[0]) {
+ throw Error(formatProdErrorMessage(490, node[0], name));
+ }
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ const currentNode = task.node;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0 // TODO check remaining slots
+ ) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ if (task.node === currentNode) {
+ // This same element suspended so we need to pop the replay we just added.
+ task.replay = replay;
+ }
+
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay;
+ } else {
+ // Let's double check that the component type matches.
+ if (type !== REACT_SUSPENSE_TYPE) {
+ const expectedType = 'Suspense';
+ throw Error(formatProdErrorMessage(490, expectedType, getComponentNameFromType(type) || 'Unknown'));
+ } // Matched a replayable path.
+
+
+ replaySuspenseBoundary(request, task, keyPath, props, node[5], node[2], node[3], node[4] === null ? [] : node[4][2], node[4] === null ? null : node[4][3]);
+ } // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+
+ replayNodes.splice(i, 1);
+ return;
+ } // We didn't find any matching nodes. We assume that this element was already
+ // rendered in the prelude and skip it.
+
+} // $FlowFixMe[missing-local-annot]
+
+function renderNodeDestructive(request, task, // The thenable state reused from the previous attempt, if any. This is almost
+// always null, except when called by retryTask.
+prevThenableState, node, childIndex) {
+ {
+ return renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex);
+ }
+} // This function by it self renders a node and consumes the task by mutating it
+// to update the current execution state.
+
+
+function renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex) {
+ if (task.replay !== null && typeof task.replay.slots === 'number') {
+ // TODO: Figure out a cheaper place than this hot path to do this check.
+ const resumeSegmentID = task.replay.slots;
+ resumeNode(request, task, resumeSegmentID, node, childIndex);
+ return;
+ } // Stash the node we're working on. We'll pick up from this task in case
+ // something suspends.
+
+
+ task.node = node;
+ task.childIndex = childIndex; // Handle object types
+
+ if (typeof node === 'object' && node !== null) {
+ switch (node.$$typeof) {
+ case REACT_ELEMENT_TYPE:
+ {
+ const element = node;
+ const type = element.type;
+ const key = element.key;
+ const props = element.props;
+ const ref = element.ref;
+ const name = getComponentNameFromType(type);
+ const keyOrIndex = key == null ? childIndex === -1 ? 0 : childIndex : key;
+ const keyPath = [task.keyPath, name, keyOrIndex];
+
+ if (task.replay !== null) {
+ replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, task.replay); // No matches found for this node. We assume it's already emitted in the
+ // prelude and skip it during the replay.
+ } else {
+ // We're doing a plain render.
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+ }
+
+ return;
+ }
+
+ case REACT_PORTAL_TYPE:
+ throw Error(formatProdErrorMessage(257));
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyNode = node;
+ const payload = lazyNode._payload;
+ const init = lazyNode._init;
+ let resolvedNode;
+
+ {
+ resolvedNode = init(payload);
+ }
+
+ renderNodeDestructive(request, task, null, resolvedNode, childIndex);
+ return;
+ }
+ }
+
+ if (isArray(node)) {
+ renderChildrenArray(request, task, node, childIndex);
+ return;
+ }
+
+ const iteratorFn = getIteratorFn(node);
+
+ if (iteratorFn) {
+
+ const iterator = iteratorFn.call(node);
+
+ if (iterator) {
+ // We need to know how many total children are in this set, so that we
+ // can allocate enough id slots to acommodate them. So we must exhaust
+ // the iterator before we start recursively rendering the children.
+ // TODO: This is not great but I think it's inherent to the id
+ // generation algorithm.
+ let step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that.
+
+ if (!step.done) {
+ const children = [];
+
+ do {
+ children.push(step.value);
+ step = iterator.next();
+ } while (!step.done);
+
+ renderChildrenArray(request, task, children, childIndex);
+ return;
+ }
+
+ return;
+ }
+ } // Usables are a valid React node type. When React encounters a Usable in
+ // a child position, it unwraps it using the same algorithm as `use`. For
+ // example, for promises, React will throw an exception to unwind the
+ // stack, then replay the component once the promise resolves.
+ //
+ // A difference from `use` is that React will keep unwrapping the value
+ // until it reaches a non-Usable type.
+ //
+ // e.g. Usable>> should resolve to T
+
+
+ const maybeUsable = node;
+
+ if (typeof maybeUsable.then === 'function') {
+ const thenable = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable), childIndex);
+ }
+
+ if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, readContext$1(context), childIndex);
+ } // $FlowFixMe[method-unbinding]
+
+
+ const childString = Object.prototype.toString.call(node);
+ throw Error(formatProdErrorMessage(31, childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString));
+ }
+
+ if (typeof node === 'string') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+
+ if (typeof node === 'number') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, '' + node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+}
+
+function replayFragment(request, task, children, childIndex) {
+ // If we're supposed follow this array, we'd expect to see a ReplayNode matching
+ // this fragment.
+ const replay = task.replay;
+ const replayNodes = replay.nodes;
+
+ for (let j = 0; j < replayNodes.length; j++) {
+ const node = replayNodes[j];
+
+ if (node[1] !== childIndex) {
+ continue;
+ } // Matched a replayable path.
+
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderChildrenArray(request, task, children, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+ // This is an error, stash the component stack if it is null.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay; // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ replayNodes.splice(j, 1);
+ break;
+ }
+}
+
+function renderChildrenArray(request, task, children, childIndex) {
+ const prevKeyPath = task.keyPath;
+
+ if (childIndex !== -1) {
+ task.keyPath = [task.keyPath, 'Fragment', childIndex];
+
+ if (task.replay !== null) {
+ replayFragment(request, // $FlowFixMe: Refined.
+ task, children, childIndex);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ const prevTreeContext = task.treeContext;
+ const totalChildren = children.length;
+
+ if (task.replay !== null) {
+ // Replay
+ // First we need to check if we have any resume slots at this level.
+ const resumeSlots = task.replay.slots;
+
+ if (resumeSlots !== null && typeof resumeSlots === 'object') {
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ const resumeSegmentID = resumeSlots[i]; // TODO: If this errors we should still continue with the next sibling.
+
+ if (typeof resumeSegmentID === 'number') {
+ resumeNode(request, task, resumeSegmentID, node, i); // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ delete resumeSlots[i];
+ } else {
+ renderNode(request, task, node, i);
+ }
+ }
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ renderNode(request, task, node, i);
+ } // Because this context is always set right before rendering every child, we
+ // only need to reset it to the previous value at the very end.
+
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+}
+
+function spawnNewSuspendedReplayTask(request, task, thenableState, x) {
+ const newTask = createReplayTask(request, thenableState, task.replay, task.node, task.childIndex, task.blockedBoundary, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+}
+
+function spawnNewSuspendedRenderTask(request, task, thenableState, x) {
+ // Something suspended, we'll need to create a new segment and resolve it later.
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ const newTask = createRenderTask(request, thenableState, task.node, task.childIndex, task.blockedBoundary, newSegment, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+} // This is a non-destructive form of rendering a node. If it suspends it spawns
+// a new task and restores the context of this task to what it was before.
+
+
+function renderNode(request, task, node, childIndex) {
+ // Snapshot the current context in case something throws to interrupt the
+ // process.
+ const previousFormatContext = task.formatContext;
+ const previousLegacyContext = task.legacyContext;
+ const previousContext = task.context;
+ const previousKeyPath = task.keyPath;
+ const previousTreeContext = task.treeContext;
+
+ let x; // Store how much we've pushed at this point so we can reset it in case something
+ // suspended partially through writing something.
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState();
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedReplayTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode.
+
+ }
+ } else {
+ // Render
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedRenderTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ }
+ }
+ } // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ // Let's terminate the rest of the tree and don't render any siblings.
+
+
+ throw x;
+}
+
+function erroredReplay(request, boundary, error, replayNodes, resumeSlots) {
+ // Erroring during a replay doesn't actually cause an error by itself because
+ // that component has already rendered. What causes the error is the resumable
+ // points that we did not yet finish which will be below the point of the reset.
+ // For example, if we're replaying a path to a Suspense boundary that is not done
+ // that doesn't error the parent Suspense boundary.
+ // This might be a bit strange that the error in a parent gets thrown at a child.
+ // We log it only once and reuse the digest.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ abortRemainingReplayNodes(request, boundary, replayNodes, resumeSlots, error, errorDigest);
+}
+
+function erroredTask(request, boundary, error) {
+ // Report the error to a global handler.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ if (boundary === null) {
+ fatalError(request, error);
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+ // so we can flush it, if the parent already flushed.
+
+
+ if (boundary.parentFlushed) {
+ // We don't have a preference where in the queue this goes since it's likely
+ // to error on the client anyway. However, intentionally client-rendered
+ // boundaries should be flushed earlier so that they can start on the client.
+ // We reuse the same queue for errors.
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function abortTaskSoft(task) {
+ // This aborts task without aborting the parent boundary that it blocks.
+ // It's used for when we didn't need this task to complete the tree.
+ // If task was needed, then it should use abortTask instead.
+ const request = this;
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ finishedTask(request, boundary, segment);
+ }
+}
+
+function abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest) {
+ const resumedBoundary = createSuspenseBoundary(request, new Set());
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = rootSegmentID;
+ resumedBoundary.status = CLIENT_RENDERED;
+ resumedBoundary.errorDigest = errorDigest;
+
+ if (resumedBoundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(resumedBoundary);
+ }
+}
+
+function abortRemainingReplayNodes(request, boundary, nodes, slots, error, errorDigest) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+
+ if (node.length === 4) {
+ abortRemainingReplayNodes(request, boundary, node[2], node[3], error, errorDigest);
+ } else {
+ const boundaryNode = node;
+ const rootSegmentID = boundaryNode[5];
+ abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest);
+ }
+ } // Empty the set, since we've cleared it now.
+
+
+ nodes.length = 0;
+
+ if (slots !== null) {
+ // We had something still to resume in the parent boundary. We must trigger
+ // the error on the parent boundary since it's not able to complete.
+ if (boundary === null) {
+ throw Error(formatProdErrorMessage(487));
+ } else if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // Empty the set
+
+
+ if (typeof slots === 'object') {
+ for (const index in slots) {
+ delete slots[index];
+ }
+ }
+ }
+}
+
+function abortTask(task, request, error) {
+ // This aborts the task and aborts the parent that it blocks, putting it into
+ // client rendered mode.
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ }
+
+ if (boundary === null) {
+ if (request.status !== CLOSING && request.status !== CLOSED) {
+ const replay = task.replay;
+
+ if (replay === null) {
+ // We didn't complete the root so we have nothing to show. We can close
+ // the request;
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ return;
+ } else {
+ // If the shell aborts during a replay, that's not a fatal error. Instead
+ // we should be able to recover by client rendering all the root boundaries in
+ // the ReplaySet.
+ replay.pendingTasks--;
+
+ if (replay.pendingTasks === 0 && replay.nodes.length > 0) {
+ const errorDigest = logRecoverableError(request, error);
+ abortRemainingReplayNodes(request, null, replay.nodes, replay.slots, error, errorDigest);
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ }
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = logRecoverableError(request, error);
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // If this boundary was still pending then we haven't already cancelled its fallbacks.
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
+
+
+ boundary.fallbackAbortableTasks.forEach(fallbackTask => abortTask(fallbackTask, request, error));
+ boundary.fallbackAbortableTasks.clear();
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeShell(request) {
+ if (request.trackedPostpones === null) {
+ // We only emit early preloads on shell completion for renders. For prerenders
+ // we wait for the entire Request to finish because we are not responding to a
+ // live request and can wait for as much data as possible.
+ // we should only be calling completeShell when the shell is complete so we
+ // just use a literal here
+ const shellComplete = true;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ } // We have completed the shell so the shell can't error anymore.
+
+
+ request.onShellError = noop;
+ const onShellReady = request.onShellReady;
+ onShellReady();
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeAll(request) {
+ // During a render the shell must be complete if the entire request is finished
+ // however during a Prerender it is possible that the shell is incomplete because
+ // it postponed. We cannot use rootPendingTasks in the prerender case because
+ // those hit zero even when the shell postpones. Instead we look at the completedRootSegment
+ const shellComplete = request.trackedPostpones === null ? // Render, we assume it is completed
+ true : // Prerender Request, we use the state of the root segment
+ request.completedRootSegment === null || request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ const onAllReady = request.onAllReady;
+ onAllReady();
+}
+
+function queueCompletedSegment(boundary, segment) {
+ if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) {
+ // This is an empty segment. There's nothing to write, so we can instead transfer the ID
+ // to the child. That way any existing references point to the child.
+ const childSegment = segment.children[0];
+ childSegment.id = segment.id;
+ childSegment.parentFlushed = true;
+
+ if (childSegment.status === COMPLETED) {
+ queueCompletedSegment(boundary, childSegment);
+ }
+ } else {
+ const completedSegments = boundary.completedSegments;
+ completedSegments.push(segment);
+ }
+}
+
+function finishedTask(request, boundary, segment) {
+ if (boundary === null) {
+ if (segment !== null && segment.parentFlushed) {
+ if (request.completedRootSegment !== null) {
+ throw Error(formatProdErrorMessage(389));
+ }
+
+ request.completedRootSegment = segment;
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status === CLIENT_RENDERED) ; else if (boundary.pendingTasks === 0) {
+ if (boundary.status === PENDING) {
+ boundary.status = COMPLETED;
+ } // This must have been the last segment we were waiting on. This boundary is now complete.
+
+
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent segment already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ }
+ }
+
+ if (boundary.parentFlushed) {
+ // The segment might be part of a segment that didn't flush yet, but if the boundary's
+ // parent flushed, we need to schedule the boundary to be emitted.
+ request.completedBoundaries.push(boundary);
+ } // We can now cancel any pending task on the fallback since we won't need to show it anymore.
+ // This needs to happen after we read the parentFlushed flags because aborting can finish
+ // work which can trigger user code, which can start flushing, which can change those flags.
+ // If the boundary was POSTPONED, we still need to finish the fallback first.
+
+
+ if (boundary.status === COMPLETED) {
+ boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
+ boundary.fallbackAbortableTasks.clear();
+ }
+ } else {
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length === 1) {
+ // This is the first time since we last flushed that we completed anything.
+ // We can schedule this boundary to emit its partially completed segments early
+ // in case the parent has already been flushed.
+ if (boundary.parentFlushed) {
+ request.partialBoundaries.push(boundary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function retryTask(request, task) {
+ {
+ const blockedBoundary = task.blockedBoundary;
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, blockedBoundary ? blockedBoundary.resources : null);
+ }
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ retryReplayTask(request, // $FlowFixMe: Refined.
+ task);
+ } else {
+ retryRenderTask(request, // $FlowFixMe: Refined.
+ task, segment);
+ }
+}
+
+function retryRenderTask(request, task, segment) {
+ if (segment.status !== PENDING) {
+ // We completed this by other means before we had a chance to retry it.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+ pushSegmentFinale(segment.chunks, request.renderState, segment.lastPushedText, segment.textEmbedded);
+ task.abortSet.delete(task);
+ segment.status = COMPLETED;
+ finishedTask(request, task.blockedBoundary, segment);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.abortSet.delete(task);
+ segment.status = ERRORED;
+ erroredTask(request, task.blockedBoundary, x);
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function retryReplayTask(request, task) {
+ if (task.replay.pendingTasks === 0) {
+ // There are no pending tasks working on this set, so we must have aborted.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ finishedTask(request, task.blockedBoundary, null);
+ } catch (thrownValue) {
+ resetHooksState();
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ erroredReplay(request, task.blockedBoundary, x, task.replay.nodes, task.replay.slots);
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function performWork(request) {
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ const prevContext = getActiveContext();
+ const prevDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = HooksDispatcher;
+ let prevCacheDispatcher;
+
+ {
+ prevCacheDispatcher = ReactCurrentCache.current;
+ ReactCurrentCache.current = DefaultCacheDispatcher;
+ }
+
+ const prevRequest = currentRequest;
+ currentRequest = request;
+
+ const prevResumableState = currentResumableState;
+ setCurrentResumableState(request.resumableState);
+
+ try {
+ const pingedTasks = request.pingedTasks;
+ let i;
+
+ for (i = 0; i < pingedTasks.length; i++) {
+ const task = pingedTasks[i];
+ retryTask(request, task);
+ }
+
+ pingedTasks.splice(0, i);
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ } finally {
+ setCurrentResumableState(prevResumableState);
+ ReactCurrentDispatcher.current = prevDispatcher;
+
+ {
+ ReactCurrentCache.current = prevCacheDispatcher;
+ }
+
+ if (prevDispatcher === HooksDispatcher) {
+ // This means that we were in a reentrant work loop. This could happen
+ // in a renderer that supports synchronous work like renderToString,
+ // when it's called from within another renderer.
+ // Normally we don't bother switching the contexts to their root/default
+ // values when leaving because we'll likely need the same or similar
+ // context again. However, when we're inside a synchronous loop like this
+ // we'll to restore the context to what it was before returning.
+ switchContext(prevContext);
+ }
+
+ currentRequest = prevRequest;
+ }
+}
+
+function flushSubtree(request, destination, segment) {
+ segment.parentFlushed = true;
+
+ switch (segment.status) {
+ case PENDING:
+ {
+ // We're emitting a placeholder for this segment to be filled in later.
+ // Therefore we'll need to assign it an ID - to refer to it by.
+ segment.id = request.nextSegmentId++; // Fallthrough
+ }
+
+ case POSTPONED:
+ {
+ const segmentID = segment.id; // When this segment finally completes it won't be embedded in text since it will flush separately
+
+ segment.lastPushedText = false;
+ segment.textEmbedded = false;
+ return writePlaceholder(destination, request.renderState, segmentID);
+ }
+
+ case COMPLETED:
+ {
+ segment.status = FLUSHED;
+ let r = true;
+ const chunks = segment.chunks;
+ let chunkIdx = 0;
+ const children = segment.children;
+
+ for (let childIdx = 0; childIdx < children.length; childIdx++) {
+ const nextChild = children[childIdx]; // Write all the chunks up until the next child.
+
+ for (; chunkIdx < nextChild.index; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ r = flushSegment(request, destination, nextChild);
+ } // Finally just write all the remaining chunks
+
+
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ if (chunkIdx < chunks.length) {
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
+ }
+
+ return r;
+ }
+
+ default:
+ {
+ throw Error(formatProdErrorMessage(390));
+ }
+ }
+}
+
+function flushSegment(request, destination, segment) {
+ const boundary = segment.boundary;
+
+ if (boundary === null) {
+ // Not a suspense boundary.
+ return flushSubtree(request, destination, segment);
+ }
+
+ boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to
+ // emit the content or the fallback now.
+
+ if (boundary.status === CLIENT_RENDERED) {
+ // Emit a client rendered suspense boundary wrapper.
+ // We never queue the inner boundary so we'll never emit its content or partial segments.
+ writeStartClientRenderedSuspenseBoundary(destination, request.renderState, boundary.errorDigest); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndClientRenderedSuspenseBoundary(destination, request.renderState);
+ } else if (boundary.status !== COMPLETED) {
+ if (boundary.status === PENDING) {
+ // For pending boundaries we lazily assign an ID to the boundary
+ // and root segment.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ }
+
+ if (boundary.completedSegments.length > 0) {
+ // If this is at least partially complete, we can queue it to be partially emitted early.
+ request.partialBoundaries.push(boundary);
+ } // This boundary is still loading. Emit a pending suspense boundary wrapper.
+
+
+ const id = boundary.rootSegmentID;
+ writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else if (boundary.byteSize > request.progressiveChunkSize) {
+ // This boundary is large and will be emitted separately so that we can progressively show
+ // other content. We add it to the queue during the flush because we have to ensure that
+ // the parent flushes first so that there's something to inject it into.
+ // We also have to make sure that it's emitted into the queue in a deterministic slot.
+ // I.e. we can't insert it here when it completes.
+ // Assign an ID to refer to the future content by.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper.
+
+ writeStartPendingSuspenseBoundary(destination, request.renderState, boundary.rootSegmentID); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else {
+ {
+ hoistResources(request.renderState, boundary.resources);
+ } // We can inline this boundary's content as a complete boundary.
+
+
+ writeStartCompletedSuspenseBoundary(destination, request.renderState);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length !== 1) {
+ throw Error(formatProdErrorMessage(391));
+ }
+
+ const contentSegment = completedSegments[0];
+ flushSegment(request, destination, contentSegment);
+ return writeEndCompletedSuspenseBoundary(destination, request.renderState);
+ }
+}
+
+function flushClientRenderedBoundary(request, destination, boundary) {
+ return writeClientRenderBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack);
+}
+
+function flushSegmentContainer(request, destination, segment) {
+ writeStartSegment(destination, request.renderState, segment.parentFormatContext, segment.id);
+ flushSegment(request, destination, segment);
+ return writeEndSegment(destination, segment.parentFormatContext);
+}
+
+function flushCompletedBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+ flushPartiallyCompletedSegment(request, destination, boundary, segment);
+ }
+
+ completedSegments.length = 0;
+
+ {
+ writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+
+ return writeCompletedBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.resources);
+}
+
+function flushPartialBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+
+ if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) {
+ i++;
+ completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority
+ // might want to write later.
+
+ return false;
+ }
+ }
+
+ completedSegments.splice(0, i);
+
+ {
+ // The way this is structured we only write resources for partial boundaries
+ // if there is no backpressure. Later before we complete the boundary we
+ // will write resources regardless of backpressure before we emit the
+ // completion instruction
+ return writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+}
+
+function flushPartiallyCompletedSegment(request, destination, boundary, segment) {
+ if (segment.status === FLUSHED) {
+ // We've already flushed this inline.
+ return true;
+ }
+
+ const segmentID = segment.id;
+
+ if (segmentID === -1) {
+ // This segment wasn't previously referred to. This happens at the root of
+ // a boundary. We make kind of a leap here and assume this is the root.
+ const rootSegmentID = segment.id = boundary.rootSegmentID;
+
+ if (rootSegmentID === -1) {
+ throw Error(formatProdErrorMessage(392));
+ }
+
+ return flushSegmentContainer(request, destination, segment);
+ } else if (segmentID === boundary.rootSegmentID) {
+ // When we emit postponed boundaries, we might have assigned the ID already
+ // but it's still the root segment so we can't inject it into the parent yet.
+ return flushSegmentContainer(request, destination, segment);
+ } else {
+ flushSegmentContainer(request, destination, segment);
+ return writeCompletedSegmentInstruction(destination, request.resumableState, request.renderState, segmentID);
+ }
+}
+
+function flushCompletedQueues(request, destination) {
+
+ try {
+ // The structure of this is to go through each queue one by one and write
+ // until the sink tells us to stop. When we should stop, we still finish writing
+ // that item fully and then yield. At that point we remove the already completed
+ // items up until the point we completed them.
+ let i;
+ const completedRootSegment = request.completedRootSegment;
+
+ if (completedRootSegment !== null) {
+ if (completedRootSegment.status === POSTPONED) {
+ // We postponed the root, so we write nothing.
+ return;
+ } else if (request.pendingRootTasks === 0) {
+ if (enableFloat) {
+ writePreamble(destination, request.resumableState, request.renderState, request.allPendingTasks === 0 && request.trackedPostpones === null);
+ }
+
+ flushSegment(request, destination, completedRootSegment);
+ request.completedRootSegment = null;
+ writeCompletedRoot(destination, request.renderState, request.resumableState);
+ } else {
+ // We haven't flushed the root yet so we don't need to check any other branches further down
+ return;
+ }
+ }
+
+ if (enableFloat) {
+ writeHoistables(destination, request.resumableState, request.renderState);
+ } // We emit client rendering instructions for already emitted boundaries first.
+ // This is so that we can signal to the client to start client rendering them as
+ // soon as possible.
+
+
+ const clientRenderedBoundaries = request.clientRenderedBoundaries;
+
+ for (i = 0; i < clientRenderedBoundaries.length; i++) {
+ const boundary = clientRenderedBoundaries[i];
+
+ if (!flushClientRenderedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ clientRenderedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries
+ // that are completely done since we can actually show them, than it is to emit
+ // any individual segments from a partially complete boundary.
+
+ const completedBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < completedBoundaries.length; i++) {
+ const boundary = completedBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ completedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before
+ // we continue with lower priorities.
+
+ completeWriting(destination);
+ beginWriting(destination); // TODO: Here we'll emit data used by hydration.
+ // Next we emit any segments of any boundaries that are partially complete
+ // but not deeply complete.
+
+ const partialBoundaries = request.partialBoundaries;
+
+ for (i = 0; i < partialBoundaries.length; i++) {
+ const boundary = partialBoundaries[i];
+
+ if (!flushPartialBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ partialBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had
+ // boundaries added to it in case they were too larged to be inlined.
+ // New ones might be added in this loop.
+
+ const largeBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < largeBoundaries.length; i++) {
+ const boundary = largeBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ largeBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ largeBoundaries.splice(0, i);
+ } finally {
+ if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because
+ // either they have pending task or they're complete.
+ ) {
+ request.flushScheduled = false;
+
+ {
+ // We write the trailing tags but only if don't have any data to resume.
+ // If we need to resume we'll write the postamble in the resume instead.
+ {
+ writePostamble(destination, request.resumableState);
+ }
+ }
+
+
+ close(destination); // We need to stop flowing now because we do not want any async contexts which might call
+ // float methods to initiate any flushes after this point
+
+ stopFlowing(request);
+ }
+ }
+}
+
+function startWork(request) {
+ request.flushScheduled = request.destination !== null;
+
+ {
+ scheduleWork(() => performWork(request));
+ }
+
+ if (request.trackedPostpones === null) {
+ // this is either a regular render or a resume. For regular render we want
+ // to call emitEarlyPreloads after the first performWork because we want
+ // are responding to a live request and need to balance sending something early
+ // (i.e. don't want for the shell to finish) but we need something to send.
+ // The only implementation of this is for DOM at the moment and during resumes nothing
+ // actually emits but the code paths here are the same.
+ // During a prerender we don't want to be too aggressive in emitting early preloads
+ // because we aren't responding to a live request and we can wait for the prerender to
+ // postpone before we emit anything.
+ {
+ scheduleWork(() => enqueueEarlyPreloadsAfterInitialWork(request));
+ }
+ }
+}
+
+function enqueueEarlyPreloadsAfterInitialWork(request) {
+ const shellComplete = request.pendingRootTasks === 0;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+
+function enqueueFlush(request) {
+ if (request.flushScheduled === false && // If there are pinged tasks we are going to flush anyway after work completes
+ request.pingedTasks.length === 0 && // If there is no destination there is nothing we can flush to. A flush will
+ // happen when we start flowing again
+ request.destination !== null) {
+ request.flushScheduled = true;
+ scheduleWork(() => {
+ // We need to existence check destination again here because it might go away
+ // in between the enqueueFlush call and the work execution
+ const destination = request.destination;
+
+ if (destination) {
+ flushCompletedQueues(request, destination);
+ } else {
+ request.flushScheduled = false;
+ }
+ });
+ }
+} // This function is intented to only be called during the pipe function for the Node builds.
+function startFlowing(request, destination) {
+ if (request.status === CLOSING) {
+ request.status = CLOSED;
+ closeWithError(destination, request.fatalError);
+ return;
+ }
+
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ if (request.destination !== null) {
+ // We're already flowing.
+ return;
+ }
+
+ request.destination = destination;
+
+ try {
+ flushCompletedQueues(request, destination);
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function stopFlowing(request) {
+ request.destination = null;
+} // This is called to early terminate a request. It puts all pending boundaries in client rendered state.
+
+function abort(request, reason) {
+ try {
+ const abortableTasks = request.abortableTasks;
+
+ if (abortableTasks.size > 0) {
+ const error = reason === undefined ? Error(formatProdErrorMessage(432)) : reason;
+ abortableTasks.forEach(task => abortTask(task, request, error));
+ abortableTasks.clear();
+ }
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function flushResources(request) {
+ enqueueFlush(request);
+}
+function getFormState(request) {
+ return request.formState;
+}
+function getResumableState(request) {
+ return request.resumableState;
+}
+function getRenderState(request) {
+ return request.renderState;
+}
+
+function onError() {// Non-fatal errors are ignored.
+}
+
+function renderToStringImpl(children, options, generateStaticMarkup, abortReason) {
+ let didFatal = false;
+ let fatalError = null;
+ let result = '';
+ const destination = {
+ // $FlowFixMe[missing-local-annot]
+ push(chunk) {
+ if (chunk !== null) {
+ result += chunk;
+ }
+
+ return true;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ destroy(error) {
+ didFatal = true;
+ fatalError = error;
+ }
+
+ };
+ let readyToStream = false;
+
+ function onShellReady() {
+ readyToStream = true;
+ }
+
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, undefined);
+ const request = createRequest(children, resumableState, createRenderState(resumableState, generateStaticMarkup), createRootFormatContext(), Infinity, onError, undefined, onShellReady, undefined, undefined, undefined);
+ startWork(request); // If anything suspended and is still pending, we'll abort it before writing.
+ // That way we write only client-rendered boundaries from the start.
+
+ abort(request, abortReason);
+ startFlowing(request, destination);
+
+ if (didFatal && fatalError !== abortReason) {
+ throw fatalError;
+ }
+
+ if (!readyToStream) {
+ // Note: This error message is the one we use on the client. It doesn't
+ // really make sense here. But this is the legacy server renderer, anyway.
+ // We're going to delete it soon.
+ throw Error(formatProdErrorMessage(426));
+ }
+
+ return result;
+}
+
+function renderToString(children, options) {
+ return renderToStringImpl(children, options, false, 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server');
+}
+
+function renderToStaticMarkup(children, options) {
+ return renderToStringImpl(children, options, true, 'The server used "renderToStaticMarkup" which does not support Suspense. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server');
+}
+
+function renderToNodeStream() {
+ throw Error(formatProdErrorMessage(207));
+}
+
+function renderToStaticNodeStream() {
+ throw Error(formatProdErrorMessage(208));
+}
+
+exports.renderToNodeStream = renderToNodeStream;
+exports.renderToStaticMarkup = renderToStaticMarkup;
+exports.renderToStaticNodeStream = renderToStaticNodeStream;
+exports.renderToString = renderToString;
+exports.version = ReactVersion;
\ No newline at end of file
diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.min.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.min.js
index 4ce5b34f7d37f..cadf2545ea635 100644
--- a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.min.js
+++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.min.js
@@ -1,13 +1,11 @@
-/**
- * @license React
- * react-dom-server-legacy.browser.production.min.js
- *
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
/*
+ React
+ react-dom-server-legacy.browser.production.min.js
+
+ Copyright (c) Meta Platforms, Inc. and affiliates.
+
+ This source code is licensed under the MIT license found in the
+ LICENSE file in the root directory of this source tree.
JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
@@ -31,168 +29,174 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
-'use strict';var ea=require("next/dist/compiled/react"),ka=require("react-dom");function p(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;c>>16)&65535)<<16)&4294967295;f=f<<15|f>>>17;f=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295;e^=f;e=e<<13|e>>>19;e=5*(e&65535)+((5*(e>>>16)&65535)<<16)&4294967295;e=(e&65535)+27492+(((e>>>16)+58964&65535)<<16)}f=0;switch(c){case 3:f^=(a.charCodeAt(b+2)&255)<<
+'use strict';var aa=require("next/dist/compiled/react"),ba=require("react-dom");function q(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;c>>16)&65535)<<16)&4294967295;f=f<<15|f>>>17;f=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295;e^=f;e=e<<13|e>>>19;e=5*(e&65535)+((5*(e>>>16)&65535)<<16)&4294967295;e=(e&65535)+27492+(((e>>>16)+58964&65535)<<16)}f=0;switch(c){case 3:f^=(a.charCodeAt(b+2)&255)<<
16;case 2:f^=(a.charCodeAt(b+1)&255)<<8;case 1:f^=a.charCodeAt(b)&255,f=3432918353*(f&65535)+((3432918353*(f>>>16)&65535)<<16)&4294967295,f=f<<15|f>>>17,e^=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295}e^=a.length;e^=e>>>16;e=2246822507*(e&65535)+((2246822507*(e>>>16)&65535)<<16)&4294967295;e^=e>>>13;e=3266489909*(e&65535)+((3266489909*(e>>>16)&65535)<<16)&4294967295;return(e^e>>>16)>>>0}
-var t=Object.assign,v=Object.prototype.hasOwnProperty,ma=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD][:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$"),za={},Aa={};
-function Ba(a){if(v.call(Aa,a))return!0;if(v.call(za,a))return!1;if(ma.test(a))return Aa[a]=!0;za[a]=!0;return!1}
-var Ca=new Set("animationIterationCount aspectRatio borderImageOutset borderImageSlice borderImageWidth boxFlex boxFlexGroup boxOrdinalGroup columnCount columns flex flexGrow flexPositive flexShrink flexNegative flexOrder gridArea gridRow gridRowEnd gridRowSpan gridRowStart gridColumn gridColumnEnd gridColumnSpan gridColumnStart fontWeight lineClamp lineHeight opacity order orphans scale tabSize widows zIndex zoom fillOpacity floodOpacity stopOpacity strokeDasharray strokeDashoffset strokeMiterlimit strokeOpacity strokeWidth MozAnimationIterationCount MozBoxFlex MozBoxFlexGroup MozLineClamp msAnimationIterationCount msFlex msZoom msFlexGrow msFlexNegative msFlexOrder msFlexPositive msFlexShrink msGridColumn msGridColumnSpan msGridRow msGridRowSpan WebkitAnimationIterationCount WebkitBoxFlex WebKitBoxFlexGroup WebkitBoxOrdinalGroup WebkitColumnCount WebkitColumns WebkitFlex WebkitFlexGrow WebkitFlexPositive WebkitFlexShrink WebkitLineClamp".split(" ")),Da=
+var t=Object.assign,y=Object.prototype.hasOwnProperty,ka=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD][:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$"),la={},ma={};
+function za(a){if(y.call(ma,a))return!0;if(y.call(la,a))return!1;if(ka.test(a))return ma[a]=!0;la[a]=!0;return!1}
+var Aa=new Set("animationIterationCount aspectRatio borderImageOutset borderImageSlice borderImageWidth boxFlex boxFlexGroup boxOrdinalGroup columnCount columns flex flexGrow flexPositive flexShrink flexNegative flexOrder gridArea gridRow gridRowEnd gridRowSpan gridRowStart gridColumn gridColumnEnd gridColumnSpan gridColumnStart fontWeight lineClamp lineHeight opacity order orphans scale tabSize widows zIndex zoom fillOpacity floodOpacity stopOpacity strokeDasharray strokeDashoffset strokeMiterlimit strokeOpacity strokeWidth MozAnimationIterationCount MozBoxFlex MozBoxFlexGroup MozLineClamp msAnimationIterationCount msFlex msZoom msFlexGrow msFlexNegative msFlexOrder msFlexPositive msFlexShrink msGridColumn msGridColumnSpan msGridRow msGridRowSpan WebkitAnimationIterationCount WebkitBoxFlex WebKitBoxFlexGroup WebkitBoxOrdinalGroup WebkitColumnCount WebkitColumns WebkitFlex WebkitFlexGrow WebkitFlexPositive WebkitFlexShrink WebkitLineClamp".split(" ")),Ba=
new Map([["acceptCharset","accept-charset"],["htmlFor","for"],["httpEquiv","http-equiv"],["crossOrigin","crossorigin"],["accentHeight","accent-height"],["alignmentBaseline","alignment-baseline"],["arabicForm","arabic-form"],["baselineShift","baseline-shift"],["capHeight","cap-height"],["clipPath","clip-path"],["clipRule","clip-rule"],["colorInterpolation","color-interpolation"],["colorInterpolationFilters","color-interpolation-filters"],["colorProfile","color-profile"],["colorRendering","color-rendering"],
["dominantBaseline","dominant-baseline"],["enableBackground","enable-background"],["fillOpacity","fill-opacity"],["fillRule","fill-rule"],["floodColor","flood-color"],["floodOpacity","flood-opacity"],["fontFamily","font-family"],["fontSize","font-size"],["fontSizeAdjust","font-size-adjust"],["fontStretch","font-stretch"],["fontStyle","font-style"],["fontVariant","font-variant"],["fontWeight","font-weight"],["glyphName","glyph-name"],["glyphOrientationHorizontal","glyph-orientation-horizontal"],["glyphOrientationVertical",
"glyph-orientation-vertical"],["horizAdvX","horiz-adv-x"],["horizOriginX","horiz-origin-x"],["imageRendering","image-rendering"],["letterSpacing","letter-spacing"],["lightingColor","lighting-color"],["markerEnd","marker-end"],["markerMid","marker-mid"],["markerStart","marker-start"],["overlinePosition","overline-position"],["overlineThickness","overline-thickness"],["paintOrder","paint-order"],["panose-1","panose-1"],["pointerEvents","pointer-events"],["renderingIntent","rendering-intent"],["shapeRendering",
"shape-rendering"],["stopColor","stop-color"],["stopOpacity","stop-opacity"],["strikethroughPosition","strikethrough-position"],["strikethroughThickness","strikethrough-thickness"],["strokeDasharray","stroke-dasharray"],["strokeDashoffset","stroke-dashoffset"],["strokeLinecap","stroke-linecap"],["strokeLinejoin","stroke-linejoin"],["strokeMiterlimit","stroke-miterlimit"],["strokeOpacity","stroke-opacity"],["strokeWidth","stroke-width"],["textAnchor","text-anchor"],["textDecoration","text-decoration"],
["textRendering","text-rendering"],["transformOrigin","transform-origin"],["underlinePosition","underline-position"],["underlineThickness","underline-thickness"],["unicodeBidi","unicode-bidi"],["unicodeRange","unicode-range"],["unitsPerEm","units-per-em"],["vAlphabetic","v-alphabetic"],["vHanging","v-hanging"],["vIdeographic","v-ideographic"],["vMathematical","v-mathematical"],["vectorEffect","vector-effect"],["vertAdvY","vert-adv-y"],["vertOriginX","vert-origin-x"],["vertOriginY","vert-origin-y"],
-["wordSpacing","word-spacing"],["writingMode","writing-mode"],["xmlnsXlink","xmlns:xlink"],["xHeight","x-height"]]),Ja=/["'&<>]/;
-function w(a){if("boolean"===typeof a||"number"===typeof a)return""+a;a=""+a;var b=Ja.exec(a);if(b){var c="",d,e=0;for(d=b.index;d ")}
-function Eb(a,b,c,d,e,f,g,h){var k=null;"function"===typeof d&&("function"===typeof d.$$FORM_ACTION?(e=Bb(b),b=d.$$FORM_ACTION(e),h=b.name,d=b.action||"",e=b.encType,f=b.method,g=b.target,k=b.data):(a.push(" ","formAction",'="',Cb,'"'),g=f=e=d=h=null,Fb(b,c)));null!=h&&F(a,"name",h);null!=d&&F(a,"formAction",d);null!=e&&F(a,"formEncType",e);null!=f&&F(a,"formMethod",f);null!=g&&F(a,"formTarget",g);return k}
-function F(a,b,c){switch(b){case "className":E(a,"class",c);break;case "tabIndex":E(a,"tabindex",c);break;case "dir":case "role":case "viewBox":case "width":case "height":E(a,b,c);break;case "style":qb(a,c);break;case "src":case "href":case "action":case "formAction":if(null==c||"function"===typeof c||"symbol"===typeof c||"boolean"===typeof c)break;a.push(" ",b,'="',w(""+c),'"');break;case "defaultValue":case "defaultChecked":case "innerHTML":case "suppressContentEditableWarning":case "suppressHydrationWarning":break;
-case "autoFocus":case "multiple":case "muted":Ab(a,b.toLowerCase(),c);break;case "xlinkHref":if("function"===typeof c||"symbol"===typeof c||"boolean"===typeof c)break;a.push(" ","xlink:href",'="',w(""+c),'"');break;case "contentEditable":case "spellCheck":case "draggable":case "value":case "autoReverse":case "externalResourcesRequired":case "focusable":case "preserveAlpha":"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'="',w(c),'"');break;case "allowFullScreen":case "async":case "autoPlay":case "controls":case "default":case "defer":case "disabled":case "disablePictureInPicture":case "disableRemotePlayback":case "formNoValidate":case "hidden":case "loop":case "noModule":case "noValidate":case "open":case "playsInline":case "readOnly":case "required":case "reversed":case "scoped":case "seamless":case "itemScope":c&&
-"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'=""');break;case "capture":case "download":!0===c?a.push(" ",b,'=""'):!1!==c&&"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'="',w(c),'"');break;case "cols":case "rows":case "size":case "span":"function"!==typeof c&&"symbol"!==typeof c&&!isNaN(c)&&1<=c&&a.push(" ",b,'="',w(c),'"');break;case "rowSpan":case "start":"function"===typeof c||"symbol"===typeof c||isNaN(c)||a.push(" ",b,'="',w(c),'"');break;case "xlinkActuate":E(a,"xlink:actuate",
-c);break;case "xlinkArcrole":E(a,"xlink:arcrole",c);break;case "xlinkRole":E(a,"xlink:role",c);break;case "xlinkShow":E(a,"xlink:show",c);break;case "xlinkTitle":E(a,"xlink:title",c);break;case "xlinkType":E(a,"xlink:type",c);break;case "xmlBase":E(a,"xml:base",c);break;case "xmlLang":E(a,"xml:lang",c);break;case "xmlSpace":E(a,"xml:space",c);break;default:if(!(2]/;
+function z(a){if("boolean"===typeof a||"number"===typeof a)return""+a;a=""+a;var b=Ca.exec(a);if(b){var c="",d,e=0;for(d=b.index;d ")}
+function Eb(a,b,c,d,e,f,g,h){var k=null;"function"===typeof d&&("function"===typeof d.$$FORM_ACTION?(e=Bb(b),b=d.$$FORM_ACTION(e),h=b.name,d=b.action||"",e=b.encType,f=b.method,g=b.target,k=b.data):(a.push(" ","formAction",'="',Cb,'"'),g=f=e=d=h=null,Fb(b,c)));null!=h&&J(a,"name",h);null!=d&&J(a,"formAction",d);null!=e&&J(a,"formEncType",e);null!=f&&J(a,"formMethod",f);null!=g&&J(a,"formTarget",g);return k}
+function J(a,b,c){switch(b){case "className":I(a,"class",c);break;case "tabIndex":I(a,"tabindex",c);break;case "dir":case "role":case "viewBox":case "width":case "height":I(a,b,c);break;case "style":qb(a,c);break;case "src":case "href":case "action":case "formAction":if(null==c||"function"===typeof c||"symbol"===typeof c||"boolean"===typeof c)break;a.push(" ",b,'="',z(""+c),'"');break;case "defaultValue":case "defaultChecked":case "innerHTML":case "suppressContentEditableWarning":case "suppressHydrationWarning":break;
+case "autoFocus":case "multiple":case "muted":Ab(a,b.toLowerCase(),c);break;case "xlinkHref":if("function"===typeof c||"symbol"===typeof c||"boolean"===typeof c)break;a.push(" ","xlink:href",'="',z(""+c),'"');break;case "contentEditable":case "spellCheck":case "draggable":case "value":case "autoReverse":case "externalResourcesRequired":case "focusable":case "preserveAlpha":"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'="',z(c),'"');break;case "allowFullScreen":case "async":case "autoPlay":case "controls":case "default":case "defer":case "disabled":case "disablePictureInPicture":case "disableRemotePlayback":case "formNoValidate":case "hidden":case "loop":case "noModule":case "noValidate":case "open":case "playsInline":case "readOnly":case "required":case "reversed":case "scoped":case "seamless":case "itemScope":c&&
+"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'=""');break;case "capture":case "download":!0===c?a.push(" ",b,'=""'):!1!==c&&"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'="',z(c),'"');break;case "cols":case "rows":case "size":case "span":"function"!==typeof c&&"symbol"!==typeof c&&!isNaN(c)&&1<=c&&a.push(" ",b,'="',z(c),'"');break;case "rowSpan":case "start":"function"===typeof c||"symbol"===typeof c||isNaN(c)||a.push(" ",b,'="',z(c),'"');break;case "xlinkActuate":I(a,"xlink:actuate",
+c);break;case "xlinkArcrole":I(a,"xlink:arcrole",c);break;case "xlinkRole":I(a,"xlink:role",c);break;case "xlinkShow":I(a,"xlink:show",c);break;case "xlinkTitle":I(a,"xlink:title",c);break;case "xlinkType":I(a,"xlink:type",c);break;case "xmlBase":I(a,"xml:base",c);break;case "xmlLang":I(a,"xml:lang",c);break;case "xmlSpace":I(a,"xml:space",c);break;default:if(!(2"))}
-function Hb(a,b,c,d,e,f,g){var h=b.rel,k=b.href,l=b.precedence;if(3===f||g||null!=b.itemProp||"string"!==typeof h||"string"!==typeof k||""===k)return K(a,b),null;if("stylesheet"===b.rel){if("string"!==typeof l||null!=b.disabled||b.onLoad||b.onError)return K(a,b);f=d.styles.get(l);g=c.styleResources.hasOwnProperty(k)?c.styleResources[k]:void 0;null!==g?(c.styleResources[k]=null,f||(f={precedence:w(l),rules:[],hrefs:[],sheets:new Map},d.styles.set(l,f)),b={state:0,props:t({},b,{"data-precedence":b.precedence,
-precedence:null})},g&&(2===g.length&&Ib(b.props,g),(c=d.preloads.stylesheets.get(k))&&0 ");return null}function Jb(a,b,c){a.push(L(c));for(var d in b)if(v.call(b,d)){var e=b[d];if(null!=e)switch(d){case "children":case "dangerouslySetInnerHTML":throw Error(p(399,c));default:F(a,d,e)}}a.push("/>");return null}
-function Kb(a,b){a.push(L("title"));var c=null,d=null,e;for(e in b)if(v.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:F(a,e,f)}}a.push(">");b=Array.isArray(c)?2>c.length?c[0]:null:c;"function"!==typeof b&&"symbol"!==typeof b&&null!==b&&void 0!==b&&a.push(w(""+b));J(a,d,c);a.push(Lb("title"));return null}
-function Mb(a,b){a.push(L("script"));var c=null,d=null,e;for(e in b)if(v.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:F(a,e,f)}}a.push(">");J(a,d,c);"string"===typeof c&&a.push(w(c));a.push(Lb("script"));return null}
-function Nb(a,b,c){a.push(L(c));var d=c=null,e;for(e in b)if(v.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:F(a,e,f)}}a.push(">");J(a,d,c);return"string"===typeof c?(a.push(w(c)),null):c}var Ob=/^[a-zA-Z][a-zA-Z:_\.\-\d]*$/,Pb=new Map;function L(a){var b=Pb.get(a);if(void 0===b){if(!Ob.test(a))throw Error(p(65,a));b="<"+a;Pb.set(a,b)}return b}
-function Qb(a,b,c,d,e,f,g){switch(b){case "div":case "span":case "svg":case "path":case "a":case "g":case "p":case "li":break;case "select":a.push(L("select"));var h=null,k=null,l;for(l in c)if(v.call(c,l)){var n=c[l];if(null!=n)switch(l){case "children":h=n;break;case "dangerouslySetInnerHTML":k=n;break;case "defaultValue":case "value":break;default:F(a,l,n)}}a.push(">");J(a,k,h);return h;case "option":var r=f.selectedValue;a.push(L("option"));var m=null,G=null,A=null,T=null,u;for(u in c)if(v.call(c,
-u)){var z=c[u];if(null!=z)switch(u){case "children":m=z;break;case "selected":A=z;break;case "dangerouslySetInnerHTML":T=z;break;case "value":G=z;default:F(a,u,z)}}if(null!=r){var q=null!==G?""+G:Gb(m);if(Ma(r))for(var aa=0;aa");J(a,T,m);return m;case "textarea":a.push(L("textarea"));var H=null,ba=null,B=null,M;for(M in c)if(v.call(c,M)){var x=c[M];if(null!=x)switch(M){case "children":B=
-x;break;case "value":H=x;break;case "defaultValue":ba=x;break;case "dangerouslySetInnerHTML":throw Error(p(91));default:F(a,M,x)}}null===H&&null!==ba&&(H=ba);a.push(">");if(null!=B){if(null!=H)throw Error(p(92));if(Ma(B)){if(1 ");null!==rb&&rb.forEach(Db,a);return null;case "button":a.push(L("button"));var pa=null,qa=null,ca=null,ra=null,sa=null,Ta=null,ta=null,Ua;for(Ua in c)if(v.call(c,Ua)){var da=c[Ua];if(null!=da)switch(Ua){case "children":pa=da;break;case "dangerouslySetInnerHTML":qa=da;break;case "name":ca=da;break;case "formAction":ra=da;break;case "formEncType":sa=da;break;case "formMethod":Ta=da;break;case "formTarget":ta=da;break;default:F(a,Ua,da)}}var Mc=Eb(a,d,e,ra,sa,Ta,ta,ca);a.push(">");null!==
-Mc&&Mc.forEach(Db,a);J(a,qa,pa);if("string"===typeof pa){a.push(w(pa));var Nc=null}else Nc=pa;return Nc;case "form":a.push(L("form"));var Va=null,Oc=null,ia=null,Wa=null,Xa=null,Ya=null,Za;for(Za in c)if(v.call(c,Za)){var ja=c[Za];if(null!=ja)switch(Za){case "children":Va=ja;break;case "dangerouslySetInnerHTML":Oc=ja;break;case "action":ia=ja;break;case "encType":Wa=ja;break;case "method":Xa=ja;break;case "target":Ya=ja;break;default:F(a,Za,ja)}}var Xb=null,Yb=null;if("function"===typeof ia)if("function"===
-typeof ia.$$FORM_ACTION){var qe=Bb(d),Ea=ia.$$FORM_ACTION(qe);ia=Ea.action||"";Wa=Ea.encType;Xa=Ea.method;Ya=Ea.target;Xb=Ea.data;Yb=Ea.name}else a.push(" ","action",'="',Cb,'"'),Ya=Xa=Wa=ia=null,Fb(d,e);null!=ia&&F(a,"action",ia);null!=Wa&&F(a,"encType",Wa);null!=Xa&&F(a,"method",Xa);null!=Ya&&F(a,"target",Ya);a.push(">");null!==Yb&&(a.push(' "),null!==Xb&&Xb.forEach(Db,a));J(a,Oc,Va);if("string"===typeof Va){a.push(w(Va));var Pc=null}else Pc=Va;return Pc;
-case "menuitem":a.push(L("menuitem"));for(var sb in c)if(v.call(c,sb)){var Qc=c[sb];if(null!=Qc)switch(sb){case "children":case "dangerouslySetInnerHTML":throw Error(p(400));default:F(a,sb,Qc)}}a.push(">");return null;case "title":if(3===f.insertionMode||f.tagScope&1||null!=c.itemProp)var Rc=Kb(a,c);else Kb(e.hoistableChunks,c),Rc=null;return Rc;case "link":return Hb(a,c,d,e,g,f.insertionMode,!!(f.tagScope&1));case "script":var Zb=c.async;if("string"!==typeof c.src||!c.src||!Zb||"function"===typeof Zb||
+function Hb(a,b,c,d,e,f,g){var h=b.rel,k=b.href,l=b.precedence;if(3===f||g||null!=b.itemProp||"string"!==typeof h||"string"!==typeof k||""===k)return M(a,b),null;if("stylesheet"===b.rel){if("string"!==typeof l||null!=b.disabled||b.onLoad||b.onError)return M(a,b);f=d.styles.get(l);g=c.styleResources.hasOwnProperty(k)?c.styleResources[k]:void 0;null!==g?(c.styleResources[k]=null,f||(f={precedence:z(l),rules:[],hrefs:[],sheets:new Map},d.styles.set(l,f)),b={state:0,props:t({},b,{"data-precedence":b.precedence,
+precedence:null})},g&&(2===g.length&&Ib(b.props,g),(c=d.preloads.stylesheets.get(k))&&0 ");return null}function Jb(a,b,c){a.push(N(c));for(var d in b)if(y.call(b,d)){var e=b[d];if(null!=e)switch(d){case "children":case "dangerouslySetInnerHTML":throw Error(q(399,c));default:J(a,d,e)}}a.push("/>");return null}
+function Kb(a,b){a.push(N("title"));var c=null,d=null,e;for(e in b)if(y.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:J(a,e,f)}}a.push(">");b=Array.isArray(c)?2>c.length?c[0]:null:c;"function"!==typeof b&&"symbol"!==typeof b&&null!==b&&void 0!==b&&a.push(z(""+b));L(a,d,c);a.push(Lb("title"));return null}
+function Mb(a,b){a.push(N("script"));var c=null,d=null,e;for(e in b)if(y.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:J(a,e,f)}}a.push(">");L(a,d,c);"string"===typeof c&&a.push(z(c));a.push(Lb("script"));return null}
+function Nb(a,b,c){a.push(N(c));var d=c=null,e;for(e in b)if(y.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:J(a,e,f)}}a.push(">");L(a,d,c);return"string"===typeof c?(a.push(z(c)),null):c}var Ob=/^[a-zA-Z][a-zA-Z:_\.\-\d]*$/,Pb=new Map;function N(a){var b=Pb.get(a);if(void 0===b){if(!Ob.test(a))throw Error(q(65,a));b="<"+a;Pb.set(a,b)}return b}
+function Qb(a,b,c,d,e,f,g){switch(b){case "div":case "span":case "svg":case "path":case "a":case "g":case "p":case "li":break;case "select":a.push(N("select"));var h=null,k=null,l;for(l in c)if(y.call(c,l)){var n=c[l];if(null!=n)switch(l){case "children":h=n;break;case "dangerouslySetInnerHTML":k=n;break;case "defaultValue":case "value":break;default:J(a,l,n)}}a.push(">");L(a,k,h);return h;case "option":var r=f.selectedValue;a.push(N("option"));var m=null,F=null,D=null,R=null,v;for(v in c)if(y.call(c,
+v)){var u=c[v];if(null!=u)switch(v){case "children":m=u;break;case "selected":D=u;break;case "dangerouslySetInnerHTML":R=u;break;case "value":F=u;default:J(a,v,u)}}if(null!=r){var p=null!==F?""+F:Gb(m);if(Ka(r))for(var G=0;G");L(a,R,m);return m;case "textarea":a.push(N("textarea"));var x=null,w=null,C=null,O;for(O in c)if(y.call(c,O)){var A=c[O];if(null!=A)switch(O){case "children":C=
+A;break;case "value":x=A;break;case "defaultValue":w=A;break;case "dangerouslySetInnerHTML":throw Error(q(91));default:J(a,O,A)}}null===x&&null!==w&&(x=w);a.push(">");if(null!=C){if(null!=x)throw Error(q(92));if(Ka(C)){if(1 ");null!==rb&&rb.forEach(Db,a);return null;case "button":a.push(N("button"));var pa=null,qa=null,ca=null,ra=null,sa=null,Ta=null,ta=null,Ua;for(Ua in c)if(y.call(c,Ua)){var da=c[Ua];if(null!=da)switch(Ua){case "children":pa=da;break;case "dangerouslySetInnerHTML":qa=da;break;case "name":ca=da;break;case "formAction":ra=da;break;case "formEncType":sa=da;break;case "formMethod":Ta=da;break;case "formTarget":ta=da;break;default:J(a,Ua,da)}}var Mc=Eb(a,d,e,ra,sa,Ta,ta,ca);a.push(">");null!==
+Mc&&Mc.forEach(Db,a);L(a,qa,pa);if("string"===typeof pa){a.push(z(pa));var Nc=null}else Nc=pa;return Nc;case "form":a.push(N("form"));var Va=null,Oc=null,ia=null,Wa=null,Xa=null,Ya=null,Za;for(Za in c)if(y.call(c,Za)){var ja=c[Za];if(null!=ja)switch(Za){case "children":Va=ja;break;case "dangerouslySetInnerHTML":Oc=ja;break;case "action":ia=ja;break;case "encType":Wa=ja;break;case "method":Xa=ja;break;case "target":Ya=ja;break;default:J(a,Za,ja)}}var Xb=null,Yb=null;if("function"===typeof ia)if("function"===
+typeof ia.$$FORM_ACTION){var se=Bb(d),Ea=ia.$$FORM_ACTION(se);ia=Ea.action||"";Wa=Ea.encType;Xa=Ea.method;Ya=Ea.target;Xb=Ea.data;Yb=Ea.name}else a.push(" ","action",'="',Cb,'"'),Ya=Xa=Wa=ia=null,Fb(d,e);null!=ia&&J(a,"action",ia);null!=Wa&&J(a,"encType",Wa);null!=Xa&&J(a,"method",Xa);null!=Ya&&J(a,"target",Ya);a.push(">");null!==Yb&&(a.push(' "),null!==Xb&&Xb.forEach(Db,a));L(a,Oc,Va);if("string"===typeof Va){a.push(z(Va));var Pc=null}else Pc=Va;return Pc;
+case "menuitem":a.push(N("menuitem"));for(var sb in c)if(y.call(c,sb)){var Qc=c[sb];if(null!=Qc)switch(sb){case "children":case "dangerouslySetInnerHTML":throw Error(q(400));default:J(a,sb,Qc)}}a.push(">");return null;case "title":if(3===f.insertionMode||f.tagScope&1||null!=c.itemProp)var Rc=Kb(a,c);else Kb(e.hoistableChunks,c),Rc=null;return Rc;case "link":return Hb(a,c,d,e,g,f.insertionMode,!!(f.tagScope&1));case "script":var Zb=c.async;if("string"!==typeof c.src||!c.src||!Zb||"function"===typeof Zb||
"symbol"===typeof Zb||c.onLoad||c.onError||3===f.insertionMode||f.tagScope&1||null!=c.itemProp)var Sc=Mb(a,c);else{var tb=c.src;if("module"===c.type){var ub=d.moduleScriptResources;var Tc=e.preloads.moduleScripts}else ub=d.scriptResources,Tc=e.preloads.scripts;var vb=ub.hasOwnProperty(tb)?ub[tb]:void 0;if(null!==vb){ub[tb]=null;var $b=c;if(vb){2===vb.length&&($b=t({},c),Ib($b,vb));var Uc=Tc.get(tb);Uc&&(Uc.length=0)}var Vc=[];e.scripts.add(Vc);Mb(Vc,$b)}g&&a.push("\x3c!-- --\x3e");Sc=null}return Sc;
-case "style":var wb=c.precedence,ua=c.href;if(3===f.insertionMode||f.tagScope&1||null!=c.itemProp||"string"!==typeof wb||"string"!==typeof ua||""===ua){a.push(L("style"));var Fa=null,Wc=null,$a;for($a in c)if(v.call(c,$a)){var xb=c[$a];if(null!=xb)switch($a){case "children":Fa=xb;break;case "dangerouslySetInnerHTML":Wc=xb;break;default:F(a,$a,xb)}}a.push(">");var ab=Array.isArray(Fa)?2>Fa.length?Fa[0]:null:Fa;"function"!==typeof ab&&"symbol"!==typeof ab&&null!==ab&&void 0!==ab&&a.push(w(""+ab));J(a,
-Wc,Fa);a.push(Lb("style"));var Xc=null}else{var va=e.styles.get(wb);if(null!==(d.styleResources.hasOwnProperty(ua)?d.styleResources[ua]:void 0)){d.styleResources[ua]=null;va?va.hrefs.push(w(ua)):(va={precedence:w(wb),rules:[],hrefs:[w(ua)],sheets:new Map},e.styles.set(wb,va));var Yc=va.rules,Ga=null,Zc=null,yb;for(yb in c)if(v.call(c,yb)){var ac=c[yb];if(null!=ac)switch(yb){case "children":Ga=ac;break;case "dangerouslySetInnerHTML":Zc=ac}}var bb=Array.isArray(Ga)?2>Ga.length?Ga[0]:null:Ga;"function"!==
-typeof bb&&"symbol"!==typeof bb&&null!==bb&&void 0!==bb&&Yc.push(w(""+bb));J(Yc,Zc,Ga)}va&&e.boundaryResources&&e.boundaryResources.styles.add(va);g&&a.push("\x3c!-- --\x3e");Xc=void 0}return Xc;case "meta":if(3===f.insertionMode||f.tagScope&1||null!=c.itemProp)var $c=Jb(a,c,"meta");else g&&a.push("\x3c!-- --\x3e"),$c="string"===typeof c.charSet?Jb(e.charsetChunks,c,"meta"):"viewport"===c.name?Jb(e.preconnectChunks,c,"meta"):Jb(e.hoistableChunks,c,"meta");return $c;case "listing":case "pre":a.push(L(b));
-var cb=null,db=null,eb;for(eb in c)if(v.call(c,eb)){var zb=c[eb];if(null!=zb)switch(eb){case "children":cb=zb;break;case "dangerouslySetInnerHTML":db=zb;break;default:F(a,eb,zb)}}a.push(">");if(null!=db){if(null!=cb)throw Error(p(60));if("object"!==typeof db||!("__html"in db))throw Error(p(61));var wa=db.__html;null!==wa&&void 0!==wa&&("string"===typeof wa&&0e.highImagePreloads.size)bc.delete(Ha),e.highImagePreloads.add(xa)}else if(!d.imageResources.hasOwnProperty(Ha)){d.imageResources[Ha]=y;var cc=c.crossOrigin;var bd="string"===typeof cc?"use-credentials"===cc?cc:"":void 0;var X=e.headers,dc;X&&0X.highImagePreloads.length)&&(dc=Rb(I,"image",{imageSrcSet:c.srcSet,imageSizes:c.sizes,crossOrigin:bd,integrity:c.integrity,nonce:c.nonce,type:c.type,fetchPriority:c.fetchPriority,
-referrerPolicy:c.refererPolicy}),2<=(X.remainingCapacity-=dc.length))?(e.resets.image[Ha]=y,X.highImagePreloads&&(X.highImagePreloads+=", "),X.highImagePreloads+=dc):(xa=[],K(xa,{rel:"preload",as:"image",href:C?void 0:I,imageSrcSet:C,imageSizes:ad,crossOrigin:bd,integrity:c.integrity,type:c.type,fetchPriority:c.fetchPriority,referrerPolicy:c.referrerPolicy}),"high"===c.fetchPriority||10>e.highImagePreloads.size?e.highImagePreloads.add(xa):(e.bulkPreloads.add(xa),bc.set(Ha,xa)))}}return Jb(a,c,"img");
+case "style":var wb=c.precedence,ua=c.href;if(3===f.insertionMode||f.tagScope&1||null!=c.itemProp||"string"!==typeof wb||"string"!==typeof ua||""===ua){a.push(N("style"));var Fa=null,Wc=null,$a;for($a in c)if(y.call(c,$a)){var xb=c[$a];if(null!=xb)switch($a){case "children":Fa=xb;break;case "dangerouslySetInnerHTML":Wc=xb;break;default:J(a,$a,xb)}}a.push(">");var ab=Array.isArray(Fa)?2>Fa.length?Fa[0]:null:Fa;"function"!==typeof ab&&"symbol"!==typeof ab&&null!==ab&&void 0!==ab&&a.push(z(""+ab));L(a,
+Wc,Fa);a.push(Lb("style"));var Xc=null}else{var va=e.styles.get(wb);if(null!==(d.styleResources.hasOwnProperty(ua)?d.styleResources[ua]:void 0)){d.styleResources[ua]=null;va?va.hrefs.push(z(ua)):(va={precedence:z(wb),rules:[],hrefs:[z(ua)],sheets:new Map},e.styles.set(wb,va));var Yc=va.rules,Ga=null,Zc=null,yb;for(yb in c)if(y.call(c,yb)){var ac=c[yb];if(null!=ac)switch(yb){case "children":Ga=ac;break;case "dangerouslySetInnerHTML":Zc=ac}}var bb=Array.isArray(Ga)?2>Ga.length?Ga[0]:null:Ga;"function"!==
+typeof bb&&"symbol"!==typeof bb&&null!==bb&&void 0!==bb&&Yc.push(z(""+bb));L(Yc,Zc,Ga)}va&&e.boundaryResources&&e.boundaryResources.styles.add(va);g&&a.push("\x3c!-- --\x3e");Xc=void 0}return Xc;case "meta":if(3===f.insertionMode||f.tagScope&1||null!=c.itemProp)var $c=Jb(a,c,"meta");else g&&a.push("\x3c!-- --\x3e"),$c="string"===typeof c.charSet?Jb(e.charsetChunks,c,"meta"):"viewport"===c.name?Jb(e.preconnectChunks,c,"meta"):Jb(e.hoistableChunks,c,"meta");return $c;case "listing":case "pre":a.push(N(b));
+var cb=null,db=null,eb;for(eb in c)if(y.call(c,eb)){var zb=c[eb];if(null!=zb)switch(eb){case "children":cb=zb;break;case "dangerouslySetInnerHTML":db=zb;break;default:J(a,eb,zb)}}a.push(">");if(null!=db){if(null!=cb)throw Error(q(60));if("object"!==typeof db||!("__html"in db))throw Error(q(61));var wa=db.__html;null!==wa&&void 0!==wa&&("string"===typeof wa&&0e.highImagePreloads.size)bc.delete(Ha),e.highImagePreloads.add(xa)}else if(!d.imageResources.hasOwnProperty(Ha)){d.imageResources[Ha]=B;var cc=c.crossOrigin;var bd="string"===typeof cc?"use-credentials"===cc?cc:"":void 0;var Z=e.headers,dc;Z&&0Z.highImagePreloads.length)&&(dc=Rb(K,"image",{imageSrcSet:c.srcSet,imageSizes:c.sizes,crossOrigin:bd,integrity:c.integrity,nonce:c.nonce,type:c.type,fetchPriority:c.fetchPriority,
+referrerPolicy:c.refererPolicy}),2<=(Z.remainingCapacity-=dc.length))?(e.resets.image[Ha]=B,Z.highImagePreloads&&(Z.highImagePreloads+=", "),Z.highImagePreloads+=dc):(xa=[],M(xa,{rel:"preload",as:"image",href:H?void 0:K,imageSrcSet:H,imageSizes:ad,crossOrigin:bd,integrity:c.integrity,type:c.type,fetchPriority:c.fetchPriority,referrerPolicy:c.referrerPolicy}),"high"===c.fetchPriority||10>e.highImagePreloads.size?e.highImagePreloads.add(xa):(e.bulkPreloads.add(xa),bc.set(Ha,xa)))}}return Jb(a,c,"img");
case "base":case "area":case "br":case "col":case "embed":case "hr":case "keygen":case "param":case "source":case "track":case "wbr":return Jb(a,c,b);case "annotation-xml":case "color-profile":case "font-face":case "font-face-src":case "font-face-uri":case "font-face-format":case "font-face-name":case "missing-glyph":break;case "head":if(2>f.insertionMode&&null===e.headChunks){e.headChunks=[];var cd=Nb(e.headChunks,c,"head")}else cd=Nb(a,c,"head");return cd;case "html":if(0===f.insertionMode&&null===
-e.htmlChunks){e.htmlChunks=[""];var dd=Nb(e.htmlChunks,c,"html")}else dd=Nb(a,c,"html");return dd;default:if(-1!==b.indexOf("-")){a.push(L(b));var ec=null,ed=null,Ia;for(Ia in c)if(v.call(c,Ia)){var ya=c[Ia];if(null!=ya){var re=Ia;switch(Ia){case "children":ec=ya;break;case "dangerouslySetInnerHTML":ed=ya;break;case "style":qb(a,ya);break;case "suppressContentEditableWarning":case "suppressHydrationWarning":break;default:Ba(Ia)&&"function"!==typeof ya&&"symbol"!==typeof ya&&a.push(" ",re,'="',w(ya),
-'"')}}}a.push(">");J(a,ed,ec);return ec}}return Nb(a,c,b)}var Sb=new Map;function Lb(a){var b=Sb.get(a);void 0===b&&(b=""+a+">",Sb.set(a,b));return b}function Tb(a,b){b=b.bootstrapChunks;for(var c=0;c ')}
+e.htmlChunks){e.htmlChunks=[""];var dd=Nb(e.htmlChunks,c,"html")}else dd=Nb(a,c,"html");return dd;default:if(-1!==b.indexOf("-")){a.push(N(b));var ec=null,ed=null,Ia;for(Ia in c)if(y.call(c,Ia)){var ya=c[Ia];if(null!=ya){var te=Ia;switch(Ia){case "children":ec=ya;break;case "dangerouslySetInnerHTML":ed=ya;break;case "style":qb(a,ya);break;case "suppressContentEditableWarning":case "suppressHydrationWarning":break;default:za(Ia)&&"function"!==typeof ya&&"symbol"!==typeof ya&&a.push(" ",te,'="',z(ya),
+'"')}}}a.push(">");L(a,ed,ec);return ec}}return Nb(a,c,b)}var Sb=new Map;function Lb(a){var b=Sb.get(a);void 0===b&&(b=""+a+">",Sb.set(a,b));return b}function Tb(a,b,c){c.bootstrapScriptContent=void 0;c.bootstrapScripts=void 0;c.bootstrapModules=void 0;b=b.bootstrapChunks;for(c=0;c ')}
function Vb(a,b,c,d){switch(c.insertionMode){case 0:case 1:case 2:return a.push('');case 3:return a.push('
');case 4:return a.push('');case 5:return a.push('');case 6:return a.push('');case 7:return a.push('');case 8:return a.push('');default:throw Error(p(397));}}
-function Wb(a,b){switch(b.insertionMode){case 0:case 1:case 2:return a.push("");case 3:return a.push("");case 4:return a.push("");case 5:return a.push("
");case 6:return a.push("
");case 7:return a.push("
");case 8:return a.push("
");default:throw Error(p(397));}}var fc=/[<\u2028\u2029]/g;
+b=d.toString(16),a.push(b),a.push('">');case 6:return a.push('');case 7:return a.push('');case 8:return a.push('');default:throw Error(q(397));}}
+function Wb(a,b){switch(b.insertionMode){case 0:case 1:case 2:return a.push("");case 3:return a.push("");case 4:return a.push("");case 5:return a.push("
");case 6:return a.push("
");case 7:return a.push("
");case 8:return a.push("");default:throw Error(q(397));}}var fc=/[<\u2028\u2029]/g;
function gc(a){return JSON.stringify(a).replace(fc,function(b){switch(b){case "<":return"\\u003c";case "\u2028":return"\\u2028";case "\u2029":return"\\u2029";default:throw Error("escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}})}var hc=/[&><\u2028\u2029]/g;
function ic(a){return JSON.stringify(a).replace(hc,function(b){switch(b){case "&":return"\\u0026";case ">":return"\\u003e";case "<":return"\\u003c";case "\u2028":return"\\u2028";case "\u2029":return"\\u2029";default:throw Error("escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}})}var jc=!1,kc=!0;
function lc(a){var b=a.rules,c=a.hrefs,d=0;if(c.length){this.push('");jc=!0;b.length=0;c.length=0}}function mc(a){return 2!==a.state?jc=!0:!1}function nc(a,b,c){jc=!1;kc=!0;b.styles.forEach(lc,a);b.stylesheets.forEach(mc);jc&&(c.stylesToHoist=!0);return kc}
-function O(a){for(var b=0;b');for(a=0;a");c.length=0;d.length=0}}
-function rc(a){if(0===a.state){a.state=1;var b=a.props;K(oc,{rel:"preload",as:"style",href:a.props.href,crossOrigin:b.crossOrigin,fetchPriority:b.fetchPriority,integrity:b.integrity,media:b.media,hrefLang:b.hrefLang,referrerPolicy:b.referrerPolicy});for(a=0;a; rel=dns-prefetch",2<=(c.remainingCapacity-=e.length));f?(d.resets.dns[a]=null,c.preconnects&&(c.preconnects+=", "),c.preconnects+=e):(e=[],K(e,{href:a,rel:"dns-prefetch"}),d.preconnects.add(e))}xc(b)}}}
-function gb(a,b){var c=Q?Q:null;if(c){var d=c.resumableState,e=c.renderState;if("string"===typeof a&&a){var f="use-credentials"===b?"credentials":"string"===typeof b?"anonymous":"default";if(!d.connectResources[f].hasOwnProperty(a)){d.connectResources[f][a]=null;d=e.headers;var g,h;if(h=d&&0; rel=preconnect";if("string"===typeof b){var k=(""+b).replace(yc,zc);h+='; crossorigin="'+k+'"'}h=(g=h,2<=(d.remainingCapacity-=g.length))}h?(e.resets.connect[f][a]=
-null,d.preconnects&&(d.preconnects+=", "),d.preconnects+=g):(f=[],K(f,{rel:"preconnect",href:a,crossOrigin:b}),e.preconnects.add(f))}xc(c)}}}
-function hb(a,b,c){var d=Q?Q:null;if(d){var e=d.resumableState,f=d.renderState;if(b&&a){switch(b){case "image":if(c){var g=c.imageSrcSet;var h=c.imageSizes;var k=c.fetchPriority}var l=g?g+"\n"+(h||""):a;if(e.imageResources.hasOwnProperty(l))return;e.imageResources[l]=y;e=f.headers;var n;e&&0; rel=preload; as="'+b+'"';for(var d in c)v.call(c,d)&&(a=c[d],"string"===typeof a&&(b+="; "+d.toLowerCase()+'="'+(""+a).replace(yc,zc)+'"'));return b}var vc=/[<>\r\n]/g;
+function uc(a,b){a.push("[");var c="[";b.stylesheets.forEach(function(d){if(2!==d.state)if(3===d.state)a.push(c),d=z(JSON.stringify(""+d.props.href)),a.push(d),a.push("]"),c=",[";else{a.push(c);var e=d.props["data-precedence"],f=d.props,g=z(JSON.stringify(""+d.props.href));a.push(g);e=""+e;a.push(",");e=z(JSON.stringify(e));a.push(e);for(var h in f)if(y.call(f,h)&&(g=f[h],null!=g))switch(h){case "href":case "rel":case "precedence":case "data-precedence":break;case "children":case "dangerouslySetInnerHTML":throw Error(q(399,"link"));
+default:a:{e=a;var k=h.toLowerCase();switch(typeof g){case "function":case "symbol":break a}switch(h){case "innerHTML":case "dangerouslySetInnerHTML":case "suppressContentEditableWarning":case "suppressHydrationWarning":case "style":break a;case "className":k="class";g=""+g;break;case "hidden":if(!1===g)break a;g="";break;case "src":case "href":g=""+g;break;default:if(2; rel=dns-prefetch",2<=(c.remainingCapacity-=e.length));f?(d.resets.dns[a]=null,c.preconnects&&(c.preconnects+=", "),c.preconnects+=e):(e=[],M(e,{href:a,rel:"dns-prefetch"}),d.preconnects.add(e))}xc(b)}}}
+function Pa(a,b){var c=T?T:null;if(c){var d=c.resumableState,e=c.renderState;if("string"===typeof a&&a){var f="use-credentials"===b?"credentials":"string"===typeof b?"anonymous":"default";if(!d.connectResources[f].hasOwnProperty(a)){d.connectResources[f][a]=null;d=e.headers;var g,h;if(h=d&&0; rel=preconnect";if("string"===typeof b){var k=(""+b).replace(yc,zc);h+='; crossorigin="'+k+'"'}h=(g=h,2<=(d.remainingCapacity-=g.length))}h?(e.resets.connect[f][a]=
+null,d.preconnects&&(d.preconnects+=", "),d.preconnects+=g):(f=[],M(f,{rel:"preconnect",href:a,crossOrigin:b}),e.preconnects.add(f))}xc(c)}}}
+function fb(a,b,c){var d=T?T:null;if(d){var e=d.resumableState,f=d.renderState;if(b&&a){switch(b){case "image":if(c){var g=c.imageSrcSet;var h=c.imageSizes;var k=c.fetchPriority}var l=g?g+"\n"+(h||""):a;if(e.imageResources.hasOwnProperty(l))return;e.imageResources[l]=B;e=f.headers;var n;e&&0; rel=preload; as="'+b+'"';for(var d in c)y.call(c,d)&&(a=c[d],"string"===typeof a&&(b+="; "+d.toLowerCase()+'="'+(""+a).replace(yc,zc)+'"'));return b}var vc=/[<>\r\n]/g;
function wc(a){switch(a){case "<":return"%3C";case ">":return"%3E";case "\n":return"%0A";case "\r":return"%0D";default:throw Error("escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}}var yc=/["';,\r\n]/g;
function zc(a){switch(a){case '"':return"%22";case "'":return"%27";case ";":return"%3B";case ",":return"%2C";case "\n":return"%0A";case "\r":return"%0D";default:throw Error("escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}}function Ac(a){this.styles.add(a)}function Bc(a){this.stylesheets.add(a)}
function Cc(a,b,c){if(b=a.onHeaders){var d=a.headers;if(d){var e=d.preconnects;d.fontPreloads&&(e&&(e+=", "),e+=d.fontPreloads);d.highImagePreloads&&(e&&(e+=", "),e+=d.highImagePreloads);if(!c){c=a.styles.values();var f=c.next();a:for(;0",htmlChunks:null,headChunks:null,externalRuntimeScript:null,bootstrapChunks:[],onHeaders:void 0,headers:null,resets:{font:{},dns:{},connect:{default:{},anonymous:{},credentials:{}},image:{},style:{}},
-charsetChunks:[],preconnectChunks:[],importMapChunks:[],preloadChunks:[],hoistableChunks:[],preconnects:e,fontPreloads:f,highImagePreloads:g,styles:h,bootstrapScripts:k,scripts:l,bulkPreloads:n,preloads:r,boundaryResources:null,stylesToHoist:!1,generateStaticMarkup:b}}function Ec(a,b,c,d){if(c.generateStaticMarkup)return a.push(w(b)),!1;""===b?a=d:(d&&a.push("\x3c!-- --\x3e"),a.push(w(b)),a=!0);return a}
+fetchPriority:h.fetchPriority,referrerPolicy:h.referrerPolicy,media:h.media});if(2<=(d.remainingCapacity-=h.length))a.resets.style[k]=B,e&&(e+=", "),e+=h,a.resets.style[k]="string"===typeof g.crossOrigin||"string"===typeof g.integrity?[g.crossOrigin,g.integrity]:B;else break a}}}e?b({Link:e}):b({});a.headers=null}}}
+function Dc(a,b){var c=a.idPrefix,d=[],e=a.bootstrapScriptContent,f=a.bootstrapScripts,g=a.bootstrapModules;void 0!==e&&d.push("');
+const startScriptSrc = stringToPrecomputedChunk('');
+/**
+ * This escaping function is designed to work with bootstrapScriptContent and importMap only.
+ * because we know we are escaping the entire script. We can avoid for instance
+ * escaping html comment string sequences that are valid javascript as well because
+ * if there are no sebsequent '); // Since we store headers as strings we deal with their length in utf16 code units
+// rather than visual characters or the utf8 encoding that is used for most binary
+// serialization. Some common HTTP servers only allow for headers to be 4kB in length.
+// We choose a default length that is likely to be well under this already limited length however
+// pathological cases may still cause the utf-8 encoding of the headers to approach this limit.
+// It should also be noted that this maximum is a soft maximum. we have not reached the limit we will
+// allow one more header to be captured which means in practice if the limit is approached it will be exceeded
+
+const DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep track of what we've already written so we can refer back to it.
+// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
+// is set, the server will send instructions via data attributes (instead of inline scripts)
+
+function createRenderState$1(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+ const inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const completeSegmentData1 = stringToPrecomputedChunk('');
+const completeBoundaryData1 = stringToPrecomputedChunk('');
+const clientRenderData1 = stringToPrecomputedChunk('
+ return writeChunkAndReturn(destination, clientRenderDataEnd);
+ }
+}
+const regexForJSStringsInInstructionScripts = /[<\u2028\u2029]/g;
+
+function escapeJSStringsForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInInstructionScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const regexForJSStringsInScripts = /[&><\u2028\u2029]/g;
+
+function escapeJSObjectForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '&':
+ return '\\u0026';
+
+ case '>':
+ return '\\u003e';
+
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(''); // Tracks whether the boundary currently flushing is flushign style tags or has any
+// stylesheet dependencies not flushed in the Preamble.
+
+let currentlyRenderingBoundaryHasStylesToHoist = false; // Acts as a return value for the forEach execution of style tag flushing.
+
+let destinationHasCapacity = true;
+
+function flushStyleTagsLateForBoundary(styleQueue) {
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs;
+
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, lateStyleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ writeChunk(this, lateStyleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, lateStyleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ destinationHasCapacity = writeChunkAndReturn(this, lateStyleTagTemplateClose); // We wrote style tags for this boundary and we may need to emit a script
+ // to hoist them.
+
+ currentlyRenderingBoundaryHasStylesToHoist = true; // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function hasStylesToHoist(stylesheet) {
+ // We need to reveal boundaries with styles whenever a stylesheet it depends on is either
+ // not flushed or flushed after the preamble (shell).
+ if (stylesheet.state !== PREAMBLE) {
+ currentlyRenderingBoundaryHasStylesToHoist = true;
+ return true;
+ }
+
+ return false;
+}
+
+function writeResourcesForBoundary(destination, boundaryResources, renderState) {
+ // Reset these on each invocation, they are only safe to read in this function
+ currentlyRenderingBoundaryHasStylesToHoist = false;
+ destinationHasCapacity = true; // Flush style tags for each precedence this boundary depends on
+
+ boundaryResources.styles.forEach(flushStyleTagsLateForBoundary, destination); // Determine if this boundary has stylesheets that need to be awaited upon completion
+
+ boundaryResources.stylesheets.forEach(hasStylesToHoist);
+
+ if (currentlyRenderingBoundaryHasStylesToHoist) {
+ renderState.stylesToHoist = true;
+ }
+
+ return destinationHasCapacity;
+}
+
+function flushResource(resource) {
+ for (let i = 0; i < resource.length; i++) {
+ writeChunk(this, resource[i]);
+ }
+
+ resource.length = 0;
+}
+
+const stylesheetFlushingQueue = [];
+
+function flushStyleInPreamble(stylesheet, key, map) {
+ // We still need to encode stylesheet chunks
+ // because unlike most Hoistables and Resources we do not eagerly encode
+ // them during render. This is because if we flush late we have to send a
+ // different encoding and we don't want to encode multiple times
+ pushLinkImpl(stylesheetFlushingQueue, stylesheet.props);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ stylesheet.state = PREAMBLE;
+}
+
+const styleTagResourceOpen1 = stringToPrecomputedChunk('');
+
+function flushStylesInPreamble(styleQueue, precedence) {
+ const hasStylesheets = styleQueue.sheets.size > 0;
+ styleQueue.sheets.forEach(flushStyleInPreamble, this);
+ styleQueue.sheets.clear();
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs; // If we don't emit any stylesheets at this precedence we still need to maintain the precedence
+ // order so even if there are no rules for style tags at this precedence we emit an empty style
+ // tag with the data-precedence attribute
+
+ if (!hasStylesheets || hrefs.length) {
+ writeChunk(this, styleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, styleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ }
+
+ writeChunk(this, styleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ writeChunk(this, styleTagResourceClose); // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function preloadLateStyle(stylesheet) {
+ if (stylesheet.state === PENDING$1) {
+ stylesheet.state = PRELOADED;
+ const preloadProps = preloadAsStylePropsFromProps(stylesheet.props.href, stylesheet.props);
+ pushLinkImpl(stylesheetFlushingQueue, preloadProps);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ }
+}
+
+function preloadLateStyles(styleQueue) {
+ styleQueue.sheets.forEach(preloadLateStyle, this);
+ styleQueue.sheets.clear();
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+
+function writePreamble(destination, resumableState, renderState, willFlushAllSegments) {
+ // This function must be called exactly once on every request
+ if (!willFlushAllSegments && renderState.externalRuntimeScript) {
+ // If the root segment is incomplete due to suspended tasks
+ // (e.g. willFlushAllSegments = false) and we are using data
+ // streaming format, ensure the external runtime is sent.
+ // (User code could choose to send this even earlier by calling
+ // preinit(...), if they know they will suspend).
+ const _renderState$external = renderState.externalRuntimeScript,
+ src = _renderState$external.src,
+ chunks = _renderState$external.chunks;
+ internalPreinitScript(resumableState, renderState, src, chunks);
+ }
+
+ const htmlChunks = renderState.htmlChunks;
+ const headChunks = renderState.headChunks;
+ let i = 0; // Emit open tags before Hoistables and Resources
+
+ if (htmlChunks) {
+ // We have an to emit as part of the preamble
+ for (i = 0; i < htmlChunks.length; i++) {
+ writeChunk(destination, htmlChunks[i]);
+ }
+
+ if (headChunks) {
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } else {
+ // We did not render a head but we emitted an so we emit one now
+ writeChunk(destination, startChunkForTag('head'));
+ writeChunk(destination, endOfStartTag);
+ }
+ } else if (headChunks) {
+ // We do not have an but we do have a
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } // Emit high priority Hoistables
+
+
+ const charsetChunks = renderState.charsetChunks;
+
+ for (i = 0; i < charsetChunks.length; i++) {
+ writeChunk(destination, charsetChunks[i]);
+ }
+
+ charsetChunks.length = 0; // emit preconnect resources
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Flush unblocked stylesheets by precedence
+
+ renderState.styles.forEach(flushStylesInPreamble, destination);
+ const importMapChunks = renderState.importMapChunks;
+
+ for (i = 0; i < importMapChunks.length; i++) {
+ writeChunk(destination, importMapChunks[i]);
+ }
+
+ importMapChunks.length = 0;
+ renderState.bootstrapScripts.forEach(flushResource, destination);
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0; // Flush closing head if necessary
+
+ if (htmlChunks && headChunks === null) {
+ // We have an rendered but no rendered. We however inserted
+ // a up above so we need to emit the now. This is safe because
+ // if the main content contained the it would also have provided a
+ // . This means that all the content inside is either or
+ // invalid HTML
+ writeChunk(destination, endChunkForTag('head'));
+ }
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+function writeHoistables(destination, resumableState, renderState) {
+ let i = 0; // Emit high priority Hoistables
+ // We omit charsetChunks because we have already sent the shell and if it wasn't
+ // already sent it is too late now.
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Preload any stylesheets. these will emit in a render instruction that follows this
+ // but we want to kick off preloading as soon as possible
+
+ renderState.styles.forEach(preloadLateStyles, destination); // We only hoist importmaps that are configured through createResponse and that will
+ // always flush in the preamble. Generally we don't expect people to render them as
+ // tags when using React but if you do they are going to be treated like regular inline
+ // scripts and flush after other hoistables which is problematic
+ // bootstrap scripts should flush above script priority but these can only flush in the preamble
+ // so we elide the code here for performance
+
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0;
+}
+function writePostamble(destination, resumableState) {
+ if (resumableState.hasBody) {
+ writeChunk(destination, endChunkForTag('body'));
+ }
+
+ if (resumableState.hasHtml) {
+ writeChunk(destination, endChunkForTag('html'));
+ }
+}
+const arrayFirstOpenBracket = stringToPrecomputedChunk('[');
+const arraySubsequentOpenBracket = stringToPrecomputedChunk(',[');
+const arrayInterstitial = stringToPrecomputedChunk(',');
+const arrayCloseBracket = stringToPrecomputedChunk(']'); // This function writes a 2D array of strings to be embedded in javascript.
+// E.g.
+// [["JS_escaped_string1", "JS_escaped_string2"]]
+
+function writeStyleResourceDependenciesInJS(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInJS(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInJS(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInJS(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+}
+
+function writeStyleResourceDependencyInJS(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedPrecedence)));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInJS(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInJS(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeName)));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeValue)));
+} // This function writes a 2D array of strings to be embedded in an attribute
+// value and read with JSON.parse in ReactDOMServerExternalRuntime.js
+// E.g.
+// [["JSON_escaped_string1", "JSON_escaped_string2"]]
+
+
+function writeStyleResourceDependenciesInAttr(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInAttr(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInAttr(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInAttr(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+}
+
+function writeStyleResourceDependencyInAttr(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedPrecedence))));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInAttr(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInAttr(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeName))));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeValue))));
+}
+/**
+ * Resources
+ */
+
+
+const PENDING$1 = 0;
+const PRELOADED = 1;
+const PREAMBLE = 2;
+const LATE = 3;
+function createBoundaryResources() {
+ return {
+ styles: new Set(),
+ stylesheets: new Set()
+ };
+}
+function setCurrentlyRenderingBoundaryResourcesTarget(renderState, boundaryResources) {
+ renderState.boundaryResources = boundaryResources;
+}
+
+function getResourceKey(href) {
+ return href;
+}
+
+function getImageResourceKey(href, imageSrcSet, imageSizes) {
+ if (imageSrcSet) {
+ return imageSrcSet + '\n' + (imageSizes || '');
+ }
+
+ return href;
+}
+
+function prefetchDNS(href) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const key = getResourceKey(href);
+
+ if (!resumableState.dnsResources.hasOwnProperty(key)) {
+ resumableState.dnsResources[key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPrefetchDNSAsHeader(href), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this as resettable in case we are prerendering and postpone in the Shell
+ renderState.resets.dns[key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ // Encode as element
+ const resource = [];
+ pushLinkImpl(resource, {
+ href,
+ rel: 'dns-prefetch'
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preconnect(href, crossOrigin) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const bucket = crossOrigin === 'use-credentials' ? 'credentials' : typeof crossOrigin === 'string' ? 'anonymous' : 'default';
+ const key = getResourceKey(href);
+
+ if (!resumableState.connectResources[bucket].hasOwnProperty(key)) {
+ resumableState.connectResources[bucket][key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreconnectAsHeader(href, crossOrigin), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this in resettableState in case we are prerending and postpone in the Shell
+ renderState.resets.connect[bucket][key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ const resource = [];
+ pushLinkImpl(resource, {
+ rel: 'preconnect',
+ href,
+ crossOrigin
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preload(href, as, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (as && href) {
+ switch (as) {
+ case 'image':
+ {
+ let imageSrcSet, imageSizes, fetchPriority;
+
+ if (options) {
+ imageSrcSet = options.imageSrcSet;
+ imageSizes = options.imageSizes;
+ fetchPriority = options.fetchPriority;
+ }
+
+ const key = getImageResourceKey(href, imageSrcSet, imageSizes);
+
+ if (resumableState.imageResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resumableState.imageResources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && fetchPriority === 'high' && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit a preload as a header so we
+ // track this to make sure we don't reset it.
+ renderState.resets.image[key] = PRELOAD_NO_CREDS;
+
+ if (headers.highImagePreloads) {
+ headers.highImagePreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.highImagePreloads += header;
+ } else {
+ // If we don't have headers to write to we have to encode as elements to flush in the head
+ // When we have imageSrcSet the browser probably cannot load the right version from headers
+ // (this should be verified by testing). For now we assume these need to go in the head
+ // as elements even if headers are available.
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ // There is a bug in Safari where imageSrcSet is not respected on preload links
+ // so we omit the href here if we have imageSrcSet b/c safari will load the wrong image.
+ // This harms older browers that do not support imageSrcSet by making their preloads not work
+ // but this population is shrinking fast and is already small so we accept this tradeoff.
+ href: imageSrcSet ? undefined : href,
+ as
+ }, options));
+
+ if (fetchPriority === 'high') {
+ renderState.highImagePreloads.add(resource);
+ } else {
+ renderState.bulkPreloads.add(resource); // Stash the resource in case we need to promote it to higher priority
+ // when an img tag is rendered
+
+ renderState.preloads.images.set(key, resource);
+ }
+ }
+
+ break;
+ }
+
+ case 'style':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.styleResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.styleResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.stylesheets.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ break;
+ }
+
+ case 'script':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.scriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ renderState.preloads.scripts.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.scriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ break;
+ }
+
+ default:
+ {
+ const key = getResourceKey(href);
+ const hasAsType = resumableState.unknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.unknownResources[as] = resources;
+ }
+
+ resources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && as === 'font' && ( // We compute the header here because we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit this preload so we
+ // track it here to prevent it from being reset.
+ renderState.resets.font[key] = PRELOAD_NO_CREDS;
+
+ if (headers.fontPreloads) {
+ headers.fontPreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.fontPreloads += header;
+ } else {
+ // We either don't have headers or we are preloading something that does
+ // not warrant elevated priority so we encode as an element.
+ const resource = [];
+
+ const props = assign({
+ rel: 'preload',
+ href,
+ as
+ }, options);
+
+ pushLinkImpl(resource, props);
+
+ switch (as) {
+ case 'font':
+ renderState.fontPreloads.add(resource);
+ break;
+ // intentional fall through
+
+ default:
+ renderState.bulkPreloads.add(resource);
+ }
+ }
+ }
+ } // If we got this far we created a new resource
+
+
+ flushResources(request);
+ }
+}
+
+function preloadModule(href, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ const key = getResourceKey(href);
+ const as = options && typeof options.as === 'string' ? options.as : 'script';
+ let resource;
+
+ switch (as) {
+ case 'script':
+ {
+ if (resumableState.moduleScriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resource = [];
+ resumableState.moduleScriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.moduleScripts.set(key, resource);
+ break;
+ }
+
+ default:
+ {
+ const hasAsType = resumableState.moduleUnknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.moduleUnknownResources[as] = resources;
+ }
+
+ resource = [];
+ resources[key] = PRELOAD_NO_CREDS;
+ }
+ }
+
+ pushLinkImpl(resource, assign({
+ rel: 'modulepreload',
+ href
+ }, options));
+ renderState.bulkPreloads.add(resource); // If we got this far we created a new resource
+
+ flushResources(request);
+ }
+}
+
+function preinitStyle(href, precedence, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ precedence = precedence || 'default';
+ const key = getResourceKey(href);
+ let styleQueue = renderState.styles.get(precedence);
+ const hasKey = resumableState.styleResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.styleResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.styleResources[key] = EXISTS; // If this is the first time we've encountered this precedence we need
+ // to create a StyleQueue
+
+ if (!styleQueue) {
+ styleQueue = {
+ precedence: stringToChunk(escapeTextForBrowser(precedence)),
+ rules: [],
+ hrefs: [],
+ sheets: new Map()
+ };
+ renderState.styles.set(precedence, styleQueue);
+ }
+
+ const resource = {
+ state: PENDING$1,
+ props: assign({
+ rel: 'stylesheet',
+ href,
+ 'data-precedence': precedence
+ }, options)
+ };
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(resource.props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.stylesheets.get(key);
+
+ if (preloadResource && preloadResource.length > 0) {
+ // The Preload for this resource was created in this render pass and has not flushed yet so
+ // we need to clear it to avoid it flushing.
+ preloadResource.length = 0;
+ } else {
+ // Either the preload resource from this render already flushed in this render pass
+ // or the preload flushed in a prior pass (prerender). In either case we need to mark
+ // this resource as already having been preloaded.
+ resource.state = PRELOADED;
+ }
+ } // We add the newly created resource to our StyleQueue and if necessary
+ // track the resource with the currently rendering boundary
+
+
+ styleQueue.sheets.set(key, resource); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+ }
+}
+
+function preinitScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.scriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.scriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.scriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.scripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+}
+
+function preinitModuleScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.moduleScriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.moduleScriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.moduleScriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ type: 'module',
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.moduleScripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+} // This function is only safe to call at Request start time since it assumes
+// that each module has not already been preloaded. If we find a need to preload
+// scripts at any other point in time we will need to check whether the preload
+// already exists and not assume it
+
+
+function preloadBootstrapScriptOrModule(resumableState, renderState, href, props) {
+
+ const key = getResourceKey(href);
+ // used to preinit the resource. If a script can be preinited then it shouldn't
+ // be a bootstrap script/module and if it is a bootstrap script/module then it
+ // must not be safe to emit early. To avoid possibly allowing for preinits of
+ // bootstrap scripts/modules we occlude these keys.
+
+
+ resumableState.scriptResources[key] = EXISTS;
+ resumableState.moduleScriptResources[key] = EXISTS;
+ const resource = [];
+ pushLinkImpl(resource, props);
+ renderState.bootstrapScripts.add(resource);
+}
+
+function internalPreinitScript(resumableState, renderState, src, chunks) {
+ const key = getResourceKey(src);
+
+ if (!resumableState.scriptResources.hasOwnProperty(key)) {
+ const resource = chunks;
+ resumableState.scriptResources[key] = EXISTS;
+ renderState.scripts.add(resource);
+ }
+
+ return;
+}
+
+function preloadAsStylePropsFromProps(href, props) {
+ return {
+ rel: 'preload',
+ as: 'style',
+ href: href,
+ crossOrigin: props.crossOrigin,
+ fetchPriority: props.fetchPriority,
+ integrity: props.integrity,
+ media: props.media,
+ hrefLang: props.hrefLang,
+ referrerPolicy: props.referrerPolicy
+ };
+}
+
+function stylesheetPropsFromRawProps(rawProps) {
+ return assign({}, rawProps, {
+ 'data-precedence': rawProps.precedence,
+ precedence: null
+ });
+}
+
+function adoptPreloadCredentials(target, preloadState) {
+ if (target.crossOrigin == null) target.crossOrigin = preloadState[0];
+ if (target.integrity == null) target.integrity = preloadState[1];
+}
+
+function getPrefetchDNSAsHeader(href) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ return "<" + escapedHref + ">; rel=dns-prefetch";
+}
+
+function getPreconnectAsHeader(href, crossOrigin) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ let value = "<" + escapedHref + ">; rel=preconnect";
+
+ if (typeof crossOrigin === 'string') {
+ const escapedCrossOrigin = escapeStringForLinkHeaderQuotedParamValueContext(crossOrigin);
+ value += "; crossorigin=\"" + escapedCrossOrigin + "\"";
+ }
+
+ return value;
+}
+
+function getPreloadAsHeader(href, as, params) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ const escapedAs = escapeStringForLinkHeaderQuotedParamValueContext(as);
+ let value = "<" + escapedHref + ">; rel=preload; as=\"" + escapedAs + "\"";
+
+ for (const paramName in params) {
+ if (hasOwnProperty.call(params, paramName)) {
+ const paramValue = params[paramName];
+
+ if (typeof paramValue === 'string') {
+ value += "; " + paramName.toLowerCase() + "=\"" + escapeStringForLinkHeaderQuotedParamValueContext(paramValue) + "\"";
+ }
+ }
+ }
+
+ return value;
+}
+
+function getStylesheetPreloadAsHeader(stylesheet) {
+ const props = stylesheet.props;
+ const preloadOptions = {
+ crossOrigin: props.crossOrigin,
+ integrity: props.integrity,
+ nonce: props.nonce,
+ type: props.type,
+ fetchPriority: props.fetchPriority,
+ referrerPolicy: props.referrerPolicy,
+ media: props.media
+ };
+ return getPreloadAsHeader(props.href, 'style', preloadOptions);
+} // This escaping function is only safe to use for href values being written into
+// a "Link" header in between `<` and `>` characters. The primary concern with the href is
+// to escape the bounding characters as well as new lines. This is unsafe to use in any other
+// context
+
+
+const regexForHrefInLinkHeaderURLContext = /[<>\r\n]/g;
+
+function escapeHrefForLinkHeaderURLContext(hrefInput) {
+
+ const coercedHref = '' + hrefInput;
+ return coercedHref.replace(regexForHrefInLinkHeaderURLContext, escapeHrefForLinkHeaderURLContextReplacer);
+}
+
+function escapeHrefForLinkHeaderURLContextReplacer(match) {
+ switch (match) {
+ case '<':
+ return '%3C';
+
+ case '>':
+ return '%3E';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+} // This escaping function is only safe to use for quoted param values in an HTTP header.
+// It is unsafe to use for any value not inside quote marks in parater value position.
+
+
+const regexForLinkHeaderQuotedParamValueContext = /["';,\r\n]/g;
+
+function escapeStringForLinkHeaderQuotedParamValueContext(value, name) {
+
+ const coerced = '' + value;
+ return coerced.replace(regexForLinkHeaderQuotedParamValueContext, escapeStringForLinkHeaderQuotedParamValueContextReplacer);
+}
+
+function escapeStringForLinkHeaderQuotedParamValueContextReplacer(match) {
+ switch (match) {
+ case '"':
+ return '%22';
+
+ case "'":
+ return '%27';
+
+ case ';':
+ return '%3B';
+
+ case ',':
+ return '%2C';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+}
+
+function hoistStyleQueueDependency(styleQueue) {
+ this.styles.add(styleQueue);
+}
+
+function hoistStylesheetDependency(stylesheet) {
+ this.stylesheets.add(stylesheet);
+}
+
+function hoistResources(renderState, source) {
+ const currentBoundaryResources = renderState.boundaryResources;
+
+ if (currentBoundaryResources) {
+ source.styles.forEach(hoistStyleQueueDependency, currentBoundaryResources);
+ source.stylesheets.forEach(hoistStylesheetDependency, currentBoundaryResources);
+ }
+} // This function is called at various times depending on whether we are rendering
+// or prerendering. In this implementation we only actually emit headers once and
+// subsequent calls are ignored. We track whether the request has a completed shell
+// to determine whether we will follow headers with a flush including stylesheets.
+// In the context of prerrender we don't have a completed shell when the request finishes
+// with a postpone in the shell. In the context of a render we don't have a completed shell
+// if this is called before the shell finishes rendering which usually will happen anytime
+// anything suspends in the shell.
+
+function emitEarlyPreloads(renderState, resumableState, shellComplete) {
+ const onHeaders = renderState.onHeaders;
+
+ if (onHeaders) {
+ const headers = renderState.headers;
+
+ if (headers) {
+ let linkHeader = headers.preconnects;
+
+ if (headers.fontPreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.fontPreloads;
+ }
+
+ if (headers.highImagePreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.highImagePreloads;
+ }
+
+ if (!shellComplete) {
+ // We use raw iterators because we want to be able to halt iteration
+ // We could refactor renderState to store these dually in arrays to
+ // make this more efficient at the cost of additional memory and
+ // write overhead. However this code only runs once per request so
+ // for now I consider this sufficient.
+ const queueIter = renderState.styles.values();
+
+ outer: for (let queueStep = queueIter.next(); headers.remainingCapacity > 0 && !queueStep.done; queueStep = queueIter.next()) {
+ const sheets = queueStep.value.sheets;
+ const sheetIter = sheets.values();
+
+ for (let sheetStep = sheetIter.next(); headers.remainingCapacity > 0 && !sheetStep.done; sheetStep = sheetIter.next()) {
+ const sheet = sheetStep.value;
+ const props = sheet.props;
+ const key = getResourceKey(props.href);
+ const header = getStylesheetPreloadAsHeader(sheet); // We mutate the capacity b/c we don't want to keep checking if later headers will fit.
+ // This means that a particularly long header might close out the header queue where later
+ // headers could still fit. We could in the future alter the behavior here based on prerender vs render
+ // since during prerender we aren't as concerned with pure runtime performance.
+
+ if ((headers.remainingCapacity -= header.length) >= 2) {
+ renderState.resets.style[key] = PRELOAD_NO_CREDS;
+
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += header; // We already track that the resource exists in resumableState however
+ // if the resumableState resets because we postponed in the shell
+ // which is what is happening in this branch if we are prerendering
+ // then we will end up resetting the resumableState. When it resets we
+ // want to record the fact that this stylesheet was already preloaded
+
+ renderState.resets.style[key] = typeof props.crossOrigin === 'string' || typeof props.integrity === 'string' ? [props.crossOrigin, props.integrity] : PRELOAD_NO_CREDS;
+ } else {
+ break outer;
+ }
+ }
+ }
+ }
+
+ if (linkHeader) {
+ onHeaders({
+ Link: linkHeader
+ });
+ } else {
+ // We still call this with no headers because a user may be using it as a signal that
+ // it React will not provide any headers
+ onHeaders({});
+ }
+
+ renderState.headers = null;
+ return;
+ }
+ }
+}
+
+function createRenderState(resumableState, generateStaticMarkup) {
+ const renderState = createRenderState$1(resumableState, undefined, undefined, undefined, undefined, undefined);
+ return {
+ // Keep this in sync with ReactFizzConfigDOM
+ placeholderPrefix: renderState.placeholderPrefix,
+ segmentPrefix: renderState.segmentPrefix,
+ boundaryPrefix: renderState.boundaryPrefix,
+ startInlineScript: renderState.startInlineScript,
+ htmlChunks: renderState.htmlChunks,
+ headChunks: renderState.headChunks,
+ externalRuntimeScript: renderState.externalRuntimeScript,
+ bootstrapChunks: renderState.bootstrapChunks,
+ onHeaders: renderState.onHeaders,
+ headers: renderState.headers,
+ resets: renderState.resets,
+ charsetChunks: renderState.charsetChunks,
+ preconnectChunks: renderState.preconnectChunks,
+ importMapChunks: renderState.importMapChunks,
+ preloadChunks: renderState.preloadChunks,
+ hoistableChunks: renderState.hoistableChunks,
+ preconnects: renderState.preconnects,
+ fontPreloads: renderState.fontPreloads,
+ highImagePreloads: renderState.highImagePreloads,
+ // usedImagePreloads: renderState.usedImagePreloads,
+ styles: renderState.styles,
+ bootstrapScripts: renderState.bootstrapScripts,
+ scripts: renderState.scripts,
+ bulkPreloads: renderState.bulkPreloads,
+ preloads: renderState.preloads,
+ boundaryResources: renderState.boundaryResources,
+ stylesToHoist: renderState.stylesToHoist,
+ // This is an extra field for the legacy renderer
+ generateStaticMarkup
+ };
+}
+
+const doctypeChunk = stringToPrecomputedChunk('');
+function pushTextInstance(target, text, renderState, textEmbedded) {
+ if (renderState.generateStaticMarkup) {
+ target.push(stringToChunk(escapeTextForBrowser(text)));
+ return false;
+ } else {
+ return pushTextInstance$1(target, text, renderState, textEmbedded);
+ }
+}
+function pushSegmentFinale(target, renderState, lastPushedText, textEmbedded) {
+ if (renderState.generateStaticMarkup) {
+ return;
+ } else {
+ return pushSegmentFinale$1(target, renderState, lastPushedText, textEmbedded);
+ }
+}
+function writeStartCompletedSuspenseBoundary(destination, renderState) {
+ if (renderState.generateStaticMarkup) {
+ // A completed boundary is done and doesn't need a representation in the HTML
+ // if we're not going to be hydrating it.
+ return true;
+ }
+
+ return writeStartCompletedSuspenseBoundary$1(destination);
+}
+function writeStartClientRenderedSuspenseBoundary(destination, renderState, // flushing these error arguments are not currently supported in this legacy streaming format.
+errorDigest, errorMessage, errorComponentStack) {
+ if (renderState.generateStaticMarkup) {
+ // A client rendered boundary is done and doesn't need a representation in the HTML
+ // since we'll never hydrate it. This is arguably an error in static generation.
+ return true;
+ }
+
+ return writeStartClientRenderedSuspenseBoundary$1(destination, renderState, errorDigest);
+}
+function writeEndCompletedSuspenseBoundary(destination, renderState) {
+ if (renderState.generateStaticMarkup) {
+ return true;
+ }
+
+ return writeEndCompletedSuspenseBoundary$1(destination);
+}
+function writeEndClientRenderedSuspenseBoundary(destination, renderState) {
+ if (renderState.generateStaticMarkup) {
+ return true;
+ }
+
+ return writeEndClientRenderedSuspenseBoundary$1(destination);
+}
+const NotPendingTransition = NotPending;
+
+// ATTENTION
+// When adding new symbols to this file,
+// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
+// The Symbol used to tag the ReactElement-like types.
+const REACT_ELEMENT_TYPE = Symbol.for('react.element');
+const REACT_PORTAL_TYPE = Symbol.for('react.portal');
+const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
+const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
+const REACT_PROFILER_TYPE = Symbol.for('react.profiler');
+const REACT_PROVIDER_TYPE = Symbol.for('react.provider');
+const REACT_CONTEXT_TYPE = Symbol.for('react.context');
+const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
+const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
+const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
+const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
+const REACT_MEMO_TYPE = Symbol.for('react.memo');
+const REACT_LAZY_TYPE = Symbol.for('react.lazy');
+const REACT_SCOPE_TYPE = Symbol.for('react.scope');
+const REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');
+const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
+const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');
+const REACT_CACHE_TYPE = Symbol.for('react.cache');
+const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value');
+const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
+const FAUX_ITERATOR_SYMBOL = '@@iterator';
+function getIteratorFn(maybeIterable) {
+ if (maybeIterable === null || typeof maybeIterable !== 'object') {
+ return null;
+ }
+
+ const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
+
+ if (typeof maybeIterator === 'function') {
+ return maybeIterator;
+ }
+
+ return null;
+}
+
+function getWrappedName(outerType, innerType, wrapperName) {
+ const displayName = outerType.displayName;
+
+ if (displayName) {
+ return displayName;
+ }
+
+ const functionName = innerType.displayName || innerType.name || '';
+ return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName;
+} // Keep in sync with react-reconciler/getComponentNameFromFiber
+
+
+function getContextName(type) {
+ return type.displayName || 'Context';
+} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+
+
+function getComponentNameFromType(type) {
+ if (type == null) {
+ // Host root, text node or just invalid type.
+ return null;
+ }
+
+ if (typeof type === 'function') {
+ return type.displayName || type.name || null;
+ }
+
+ if (typeof type === 'string') {
+ return type;
+ }
+
+ switch (type) {
+ case REACT_FRAGMENT_TYPE:
+ return 'Fragment';
+
+ case REACT_PORTAL_TYPE:
+ return 'Portal';
+
+ case REACT_PROFILER_TYPE:
+ return 'Profiler';
+
+ case REACT_STRICT_MODE_TYPE:
+ return 'StrictMode';
+
+ case REACT_SUSPENSE_TYPE:
+ return 'Suspense';
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ return 'SuspenseList';
+
+ case REACT_CACHE_TYPE:
+ {
+ return 'Cache';
+ }
+
+ }
+
+ if (typeof type === 'object') {
+ switch (type.$$typeof) {
+ case REACT_CONTEXT_TYPE:
+ const context = type;
+ return getContextName(context) + '.Consumer';
+
+ case REACT_PROVIDER_TYPE:
+ const provider = type;
+ return getContextName(provider._context) + '.Provider';
+
+ case REACT_FORWARD_REF_TYPE:
+ return getWrappedName(type, type.render, 'ForwardRef');
+
+ case REACT_MEMO_TYPE:
+ const outerName = type.displayName || null;
+
+ if (outerName !== null) {
+ return outerName;
+ }
+
+ return getComponentNameFromType(type.type) || 'Memo';
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyComponent = type;
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+
+ try {
+ return getComponentNameFromType(init(payload));
+ } catch (x) {
+ return null;
+ }
+ }
+
+ }
+ }
+
+ return null;
+}
+
+const emptyContextObject = {};
+
+function getMaskedContext(type, unmaskedContext) {
+ {
+ const contextTypes = type.contextTypes;
+
+ if (!contextTypes) {
+ return emptyContextObject;
+ }
+
+ const context = {};
+
+ for (const key in contextTypes) {
+ context[key] = unmaskedContext[key];
+ }
+
+ return context;
+ }
+}
+function processChildContext(instance, type, parentContext, childContextTypes) {
+ {
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
+ if (typeof instance.getChildContext !== 'function') {
+
+ return parentContext;
+ }
+
+ const childContext = instance.getChildContext();
+
+ for (const contextKey in childContext) {
+ if (!(contextKey in childContextTypes)) {
+ throw new Error((getComponentNameFromType(type) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes.");
+ }
+ }
+
+ return assign({}, parentContext, childContext);
+ }
+}
+
+// Forming a reverse tree.
+// The structure of a context snapshot is an implementation of this file.
+// Currently, it's implemented as tracking the current active node.
+
+
+const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
+// This global (actually thread local) state represents what state all those "current",
+// fields are currently in.
+
+let currentActiveSnapshot = null;
+
+function popNode(prev) {
+ {
+ prev.context._currentValue2 = prev.parentValue;
+ }
+}
+
+function pushNode(next) {
+ {
+ next.context._currentValue2 = next.value;
+ }
+}
+
+function popToNearestCommonAncestor(prev, next) {
+ if (prev === next) ; else {
+ popNode(prev);
+ const parentPrev = prev.parent;
+ const parentNext = next.parent;
+
+ if (parentPrev === null) {
+ if (parentNext !== null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+ } else {
+ if (parentNext === null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+
+ popToNearestCommonAncestor(parentPrev, parentNext);
+ } // On the way back, we push the new ones that weren't common.
+
+
+ pushNode(next);
+ }
+}
+
+function popAllPrevious(prev) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev !== null) {
+ popAllPrevious(parentPrev);
+ }
+}
+
+function pushAllNext(next) {
+ const parentNext = next.parent;
+
+ if (parentNext !== null) {
+ pushAllNext(parentNext);
+ }
+
+ pushNode(next);
+}
+
+function popPreviousToCommonLevel(prev, next) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (parentPrev.depth === next.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(parentPrev, next);
+ } else {
+ // We must still be deeper.
+ popPreviousToCommonLevel(parentPrev, next);
+ }
+}
+
+function popNextToCommonLevel(prev, next) {
+ const parentNext = next.parent;
+
+ if (parentNext === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (prev.depth === parentNext.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(prev, parentNext);
+ } else {
+ // We must still be deeper.
+ popNextToCommonLevel(prev, parentNext);
+ }
+
+ pushNode(next);
+} // Perform context switching to the new snapshot.
+// To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
+// updating all the context's current values. That way reads, always just read the current value.
+// At the cost of updating contexts even if they're never read by this subtree.
+
+
+function switchContext(newSnapshot) {
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
+ // We also need to update any new contexts that are now on the stack with the deepest value.
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
+ // for that. Therefore this algorithm is recursive.
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
+ // 3) Then we reapply new contexts on the way back up the stack.
+ const prev = currentActiveSnapshot;
+ const next = newSnapshot;
+
+ if (prev !== next) {
+ if (prev === null) {
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
+ pushAllNext(next);
+ } else if (next === null) {
+ popAllPrevious(prev);
+ } else if (prev.depth === next.depth) {
+ popToNearestCommonAncestor(prev, next);
+ } else if (prev.depth > next.depth) {
+ popPreviousToCommonLevel(prev, next);
+ } else {
+ popNextToCommonLevel(prev, next);
+ }
+
+ currentActiveSnapshot = next;
+ }
+}
+function pushProvider(context, nextValue) {
+ let prevValue;
+
+ {
+ prevValue = context._currentValue2;
+ context._currentValue2 = nextValue;
+ }
+
+ const prevNode = currentActiveSnapshot;
+ const newNode = {
+ parent: prevNode,
+ depth: prevNode === null ? 0 : prevNode.depth + 1,
+ context: context,
+ parentValue: prevValue,
+ value: nextValue
+ };
+ currentActiveSnapshot = newNode;
+ return newNode;
+}
+function popProvider(context) {
+ const prevSnapshot = currentActiveSnapshot;
+
+ if (prevSnapshot === null) {
+ throw new Error('Tried to pop a Context at the root of the app. This is a bug in React.');
+ }
+
+ {
+ const value = prevSnapshot.parentValue;
+
+ if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) {
+ prevSnapshot.context._currentValue2 = prevSnapshot.context._defaultValue;
+ } else {
+ prevSnapshot.context._currentValue2 = value;
+ }
+ }
+
+ return currentActiveSnapshot = prevSnapshot.parent;
+}
+function getActiveContext() {
+ return currentActiveSnapshot;
+}
+function readContext$1(context) {
+ const value = context._currentValue2;
+ return value;
+}
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ *
+ * Note that this module is currently shared and assumed to be stateless.
+ * If this becomes an actual Map, that will break.
+ */
+function get(key) {
+ return key._reactInternals;
+}
+function set(key, value) {
+ key._reactInternals = value;
+}
+
+const classComponentUpdater = {
+ isMounted(inst) {
+ return false;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueSetState(inst, payload, callback) {
+ const internals = get(inst);
+
+ if (internals.queue === null) ; else {
+ internals.queue.push(payload);
+ }
+ },
+
+ enqueueReplaceState(inst, payload, callback) {
+ const internals = get(inst);
+ internals.replace = true;
+ internals.queue = [payload];
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueForceUpdate(inst, callback) {
+ }
+
+};
+
+function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) {
+ const partialState = getDerivedStateFromProps(nextProps, prevState);
+
+
+ const newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);
+ return newState;
+}
+
+function constructClassInstance(ctor, props, maskedLegacyContext) {
+ let context = emptyContextObject;
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ context = readContext$1(contextType);
+ } else {
+ context = maskedLegacyContext;
+ }
+
+ const instance = new ctor(props, context);
+
+ return instance;
+}
+
+function callComponentWillMount(type, instance) {
+ const oldState = instance.state;
+
+ if (typeof instance.componentWillMount === 'function') {
+
+ instance.componentWillMount();
+ }
+
+ if (typeof instance.UNSAFE_componentWillMount === 'function') {
+ instance.UNSAFE_componentWillMount();
+ }
+
+ if (oldState !== instance.state) {
+
+ classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
+ }
+}
+
+function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) {
+ if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
+ const oldQueue = internalInstance.queue;
+ const oldReplace = internalInstance.replace;
+ internalInstance.queue = null;
+ internalInstance.replace = false;
+
+ if (oldReplace && oldQueue.length === 1) {
+ inst.state = oldQueue[0];
+ } else {
+ let nextState = oldReplace ? oldQueue[0] : inst.state;
+ let dontMutate = true;
+
+ for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
+ const partial = oldQueue[i];
+ const partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial;
+
+ if (partialState != null) {
+ if (dontMutate) {
+ dontMutate = false;
+ nextState = assign({}, nextState, partialState);
+ } else {
+ assign(nextState, partialState);
+ }
+ }
+ }
+
+ inst.state = nextState;
+ }
+ } else {
+ internalInstance.queue = null;
+ }
+} // Invokes the mount life-cycles on a previously never rendered instance.
+
+
+function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) {
+
+ const initialState = instance.state !== undefined ? instance.state : null;
+ instance.updater = classComponentUpdater;
+ instance.props = newProps;
+ instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway.
+ // The internal instance will be used to manage updates that happen during this mount.
+
+ const internalInstance = {
+ queue: [],
+ replace: false
+ };
+ set(instance, internalInstance);
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ instance.context = readContext$1(contextType);
+ } else {
+ instance.context = maskedLegacyContext;
+ }
+
+ const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
+
+ if (typeof getDerivedStateFromProps === 'function') {
+ instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps);
+ } // In order to support react-lifecycles-compat polyfilled components,
+ // Unsafe lifecycles should not be invoked for components using the new APIs.
+
+
+ if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
+ callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's
+ // process them now.
+
+ processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext);
+ }
+}
+
+// Ids are base 32 strings whose binary representation corresponds to the
+// position of a node in a tree.
+// Every time the tree forks into multiple children, we add additional bits to
+// the left of the sequence that represent the position of the child within the
+// current level of children.
+//
+// 00101 00010001011010101
+// ╰─┬─╯ ╰───────┬───────╯
+// Fork 5 of 20 Parent id
+//
+// The leading 0s are important. In the above example, you only need 3 bits to
+// represent slot 5. However, you need 5 bits to represent all the forks at
+// the current level, so we must account for the empty bits at the end.
+//
+// For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise,
+// the zeroth id at a level would be indistinguishable from its parent.
+//
+// If a node has only one child, and does not materialize an id (i.e. does not
+// contain a useId hook), then we don't need to allocate any space in the
+// sequence. It's treated as a transparent indirection. For example, these two
+// trees produce the same ids:
+//
+// <> <>
+//
+//
+// >
+//
+// >
+//
+// However, we cannot skip any node that materializes an id. Otherwise, a parent
+// id that does not fork would be indistinguishable from its child id. For
+// example, this tree does not fork, but the parent and child must have
+// different ids.
+//
+//
+//
+//
+//
+// To handle this scenario, every time we materialize an id, we allocate a
+// new level with a single slot. You can think of this as a fork with only one
+// prong, or an array of children with length 1.
+//
+// It's possible for the size of the sequence to exceed 32 bits, the max
+// size for bitwise operations. When this happens, we make more room by
+// converting the right part of the id to a string and storing it in an overflow
+// variable. We use a base 32 string representation, because 32 is the largest
+// power of 2 that is supported by toString(). We want the base to be large so
+// that the resulting ids are compact, and we want the base to be a power of 2
+// because every log2(base) bits corresponds to a single character, i.e. every
+// log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without
+// affecting the final result.
+const emptyTreeContext = {
+ id: 1,
+ overflow: ''
+};
+function getTreeId(context) {
+ const overflow = context.overflow;
+ const idWithLeadingBit = context.id;
+ const id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);
+ return id.toString(32) + overflow;
+}
+function pushTreeContext(baseContext, totalChildren, index) {
+ const baseIdWithLeadingBit = baseContext.id;
+ const baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part
+ // of the id; we use it to account for leading 0s.
+
+ const baseLength = getBitLength(baseIdWithLeadingBit) - 1;
+ const baseId = baseIdWithLeadingBit & ~(1 << baseLength);
+ const slot = index + 1;
+ const length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into
+ // consideration the leading 1 we use to mark the end of the sequence.
+
+ if (length > 30) {
+ // We overflowed the bitwise-safe range. Fall back to slower algorithm.
+ // This branch assumes the length of the base id is greater than 5; it won't
+ // work for smaller ids, because you need 5 bits per character.
+ //
+ // We encode the id in multiple steps: first the base id, then the
+ // remaining digits.
+ //
+ // Each 5 bit sequence corresponds to a single base 32 character. So for
+ // example, if the current id is 23 bits long, we can convert 20 of those
+ // bits into a string of 4 characters, with 3 bits left over.
+ //
+ // First calculate how many bits in the base id represent a complete
+ // sequence of characters.
+ const numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.
+
+ const newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.
+
+ const newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.
+
+ const restOfBaseId = baseId >> numberOfOverflowBits;
+ const restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because
+ // we made more room, this time it won't overflow.
+
+ const restOfLength = getBitLength(totalChildren) + restOfBaseLength;
+ const restOfNewBits = slot << restOfBaseLength;
+ const id = restOfNewBits | restOfBaseId;
+ const overflow = newOverflow + baseOverflow;
+ return {
+ id: 1 << restOfLength | id,
+ overflow
+ };
+ } else {
+ // Normal path
+ const newBits = slot << baseLength;
+ const id = newBits | baseId;
+ const overflow = baseOverflow;
+ return {
+ id: 1 << length | id,
+ overflow
+ };
+ }
+}
+
+function getBitLength(number) {
+ return 32 - clz32(number);
+}
+
+function getLeadingBit(id) {
+ return 1 << getBitLength(id) - 1;
+} // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback.
+
+
+const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.
+// Based on:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+const log = Math.log;
+const LN2 = Math.LN2;
+
+function clz32Fallback(x) {
+ const asUint = x >>> 0;
+
+ if (asUint === 0) {
+ return 32;
+ }
+
+ return 31 - (log(asUint) / LN2 | 0) | 0;
+}
+
+// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
+// changes to one module should be reflected in the others.
+// TODO: Rename this module and the corresponding Fiber one to "Thenable"
+// instead of "Wakeable". Or some other more appropriate name.
+// An error that is thrown (e.g. by `use`) to trigger Suspense. If we
+// detect this is caught by userspace, we'll log a warning in development.
+const SuspenseException = new Error("Suspense Exception: This is not a real error! It's an implementation " + 'detail of `use` to interrupt the current render. You must either ' + 'rethrow it immediately, or move the `use` call outside of the ' + '`try/catch` block. Capturing without rethrowing will lead to ' + 'unexpected behavior.\n\n' + 'To handle async errors, wrap your component in an error boundary, or ' + "call the promise's `.catch` method and pass the result to `use`");
+function createThenableState() {
+ // The ThenableState is created the first time a component suspends. If it
+ // suspends again, we'll reuse the same state.
+ return [];
+}
+
+function noop$2() {}
+
+function trackUsedThenable(thenableState, thenable, index) {
+ const previous = thenableState[index];
+
+ if (previous === undefined) {
+ thenableState.push(thenable);
+ } else {
+ if (previous !== thenable) {
+ // Reuse the previous thenable, and drop the new one. We can assume
+ // they represent the same value, because components are idempotent.
+ // Avoid an unhandled rejection errors for the Promises that we'll
+ // intentionally ignore.
+ thenable.then(noop$2, noop$2);
+ thenable = previous;
+ }
+ } // We use an expando to track the status and result of a thenable so that we
+ // can synchronously unwrap the value. Think of this as an extension of the
+ // Promise API, or a custom interface that is a superset of Thenable.
+ //
+ // If the thenable doesn't have a status, set it to "pending" and attach
+ // a listener that will update its status and result when it resolves.
+
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledValue = thenable.value;
+ return fulfilledValue;
+ }
+
+ case 'rejected':
+ {
+ const rejectedError = thenable.reason;
+ throw rejectedError;
+ }
+
+ default:
+ {
+ if (typeof thenable.status === 'string') ; else {
+ const pendingThenable = thenable;
+ pendingThenable.status = 'pending';
+ pendingThenable.then(fulfilledValue => {
+ if (thenable.status === 'pending') {
+ const fulfilledThenable = thenable;
+ fulfilledThenable.status = 'fulfilled';
+ fulfilledThenable.value = fulfilledValue;
+ }
+ }, error => {
+ if (thenable.status === 'pending') {
+ const rejectedThenable = thenable;
+ rejectedThenable.status = 'rejected';
+ rejectedThenable.reason = error;
+ }
+ }); // Check one more time in case the thenable resolved synchronously
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledThenable = thenable;
+ return fulfilledThenable.value;
+ }
+
+ case 'rejected':
+ {
+ const rejectedThenable = thenable;
+ throw rejectedThenable.reason;
+ }
+ }
+ } // Suspend.
+ //
+ // Throwing here is an implementation detail that allows us to unwind the
+ // call stack. But we shouldn't allow it to leak into userspace. Throw an
+ // opaque placeholder value instead of the actual thenable. If it doesn't
+ // get captured by the work loop, log a warning, because that means
+ // something in userspace must have caught it.
+
+
+ suspendedThenable = thenable;
+ throw SuspenseException;
+ }
+ }
+} // This is used to track the actual thenable that suspended so it can be
+// passed to the rest of the Suspense implementation — which, for historical
+// reasons, expects to receive a thenable.
+
+let suspendedThenable = null;
+function getSuspendedThenable() {
+ // This is called right after `use` suspends by throwing an exception. `use`
+ // throws an opaque value instead of the thenable itself so that it can't be
+ // caught in userspace. Then the work loop accesses the actual thenable using
+ // this function.
+ if (suspendedThenable === null) {
+ throw new Error('Expected a suspended thenable. This is a bug in React. Please file ' + 'an issue.');
+ }
+
+ const thenable = suspendedThenable;
+ suspendedThenable = null;
+ return thenable;
+}
+
+/**
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+ */
+function is(x, y) {
+ return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
+ ;
+}
+
+const objectIs = // $FlowFixMe[method-unbinding]
+typeof Object.is === 'function' ? Object.is : is;
+
+let currentlyRenderingComponent = null;
+let currentlyRenderingTask = null;
+let currentlyRenderingRequest = null;
+let currentlyRenderingKeyPath = null;
+let firstWorkInProgressHook = null;
+let workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook
+
+let isReRender = false; // Whether an update was scheduled during the currently executing render pass.
+
+let didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component
+
+let localIdCounter = 0; // Chunks that should be pushed to the stream once the component
+// finishes rendering.
+// Counts the number of useFormState calls in this component
+
+let formStateCounter = 0; // The index of the useFormState hook that matches the one passed in at the
+// root during an MPA navigation, if any.
+
+let formStateMatchingIndex = -1; // Counts the number of use(thenable) calls in this component
+
+let thenableIndexCounter = 0;
+let thenableState = null; // Lazily created map of render-phase updates
+
+let renderPhaseUpdates = null; // Counter to prevent infinite loops.
+
+let numberOfReRenders = 0;
+const RE_RENDER_LIMIT = 25;
+
+function resolveCurrentlyRenderingComponent() {
+ if (currentlyRenderingComponent === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + '2. You might be breaking the Rules of Hooks\n' + '3. You might have more than one copy of React in the same app\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.');
+ }
+
+ return currentlyRenderingComponent;
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+
+ return false;
+ }
+
+
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ if (objectIs(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+function createHook() {
+ if (numberOfReRenders > 0) {
+ throw new Error('Rendered more hooks than during the previous render');
+ }
+
+ return {
+ memoizedState: null,
+ queue: null,
+ next: null
+ };
+}
+
+function createWorkInProgressHook() {
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ if (firstWorkInProgressHook === null) {
+ isReRender = false;
+ firstWorkInProgressHook = workInProgressHook = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = firstWorkInProgressHook;
+ }
+ } else {
+ if (workInProgressHook.next === null) {
+ isReRender = false; // Append to the end of the list
+
+ workInProgressHook = workInProgressHook.next = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = workInProgressHook.next;
+ }
+ }
+
+ return workInProgressHook;
+}
+
+function prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState) {
+ currentlyRenderingComponent = componentIdentity;
+ currentlyRenderingTask = task;
+ currentlyRenderingRequest = request;
+ currentlyRenderingKeyPath = keyPath;
+ // didScheduleRenderPhaseUpdate = false;
+ // firstWorkInProgressHook = null;
+ // numberOfReRenders = 0;
+ // renderPhaseUpdates = null;
+ // workInProgressHook = null;
+
+
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ thenableState = prevThenableState;
+}
+function finishHooks(Component, props, children, refOrContext) {
+ // This must be called after every function component to prevent hooks from
+ // being used in classes.
+ while (didScheduleRenderPhaseUpdate) {
+ // Updates were scheduled during the render phase. They are stored in
+ // the `renderPhaseUpdates` map. Call the component again, reusing the
+ // work-in-progress hooks and applying the additional updates on top. Keep
+ // restarting until no more updates are scheduled.
+ didScheduleRenderPhaseUpdate = false;
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ numberOfReRenders += 1; // Start over from the beginning of the list
+
+ workInProgressHook = null;
+ children = Component(props, refOrContext);
+ }
+
+ resetHooksState();
+ return children;
+}
+function getThenableStateAfterSuspending() {
+ const state = thenableState;
+ thenableState = null;
+ return state;
+}
+function checkDidRenderIdHook() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ const didRenderIdHook = localIdCounter !== 0;
+ return didRenderIdHook;
+}
+function getFormStateCount() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateCounter;
+}
+function getFormStateMatchingIndex() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateMatchingIndex;
+} // Reset the internal hooks state if an error occurs while rendering a component
+
+function resetHooksState() {
+
+ currentlyRenderingComponent = null;
+ currentlyRenderingTask = null;
+ currentlyRenderingRequest = null;
+ currentlyRenderingKeyPath = null;
+ didScheduleRenderPhaseUpdate = false;
+ firstWorkInProgressHook = null;
+ numberOfReRenders = 0;
+ renderPhaseUpdates = null;
+ workInProgressHook = null;
+}
+
+function readContext(context) {
+
+ return readContext$1(context);
+}
+
+function useContext(context) {
+
+ resolveCurrentlyRenderingComponent();
+ return readContext$1(context);
+}
+
+function basicStateReducer(state, action) {
+ // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
+ return typeof action === 'function' ? action(state) : action;
+}
+
+function useState(initialState) {
+
+ return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers
+ initialState);
+}
+function useReducer(reducer, initialArg, init) {
+
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+
+ if (isReRender) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ // current hook.
+ const queue = workInProgressHook.queue;
+ const dispatch = queue.dispatch;
+
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate !== undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.delete(queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ let newState = workInProgressHook.memoizedState;
+ let update = firstRenderPhaseUpdate;
+
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ const action = update.action;
+
+ newState = reducer(newState, action);
+
+
+ update = update.next;
+ } while (update !== null); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ workInProgressHook.memoizedState = newState;
+ return [newState, dispatch];
+ }
+ } // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ return [workInProgressHook.memoizedState, dispatch];
+ } else {
+
+ let initialState;
+
+ if (reducer === basicStateReducer) {
+ // Special case for `useState`.
+ initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
+ } else {
+ initialState = init !== undefined ? init(initialArg) : initialArg;
+ }
+
+
+ workInProgressHook.memoizedState = initialState; // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ const queue = workInProgressHook.queue = {
+ last: null,
+ dispatch: null
+ };
+ const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ return [workInProgressHook.memoizedState, dispatch];
+ }
+}
+
+function useMemo(nextCreate, deps) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const nextDeps = deps === undefined ? null : deps;
+
+ if (workInProgressHook !== null) {
+ const prevState = workInProgressHook.memoizedState;
+
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ const prevDeps = prevState[1];
+
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ }
+
+ const nextValue = nextCreate();
+
+
+ workInProgressHook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function useRef(initialValue) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const previousRef = workInProgressHook.memoizedState;
+
+ if (previousRef === null) {
+ const ref = {
+ current: initialValue
+ };
+
+
+ workInProgressHook.memoizedState = ref;
+ return ref;
+ } else {
+ return previousRef;
+ }
+}
+
+function dispatchAction(componentIdentity, queue, action) {
+ if (numberOfReRenders >= RE_RENDER_LIMIT) {
+ throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.');
+ }
+
+ if (componentIdentity === currentlyRenderingComponent) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ const update = {
+ action,
+ next: null
+ };
+
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate === undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+
+ lastRenderPhaseUpdate.next = update;
+ }
+ }
+}
+
+function useCallback(callback, deps) {
+ return useMemo(() => callback, deps);
+}
+
+function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
+ if (getServerSnapshot === undefined) {
+ throw new Error('Missing getServerSnapshot, which is required for ' + 'server-rendered content. Will revert to client rendering.');
+ }
+
+ return getServerSnapshot();
+}
+
+function useDeferredValue(value, initialValue) {
+ resolveCurrentlyRenderingComponent();
+
+ {
+ return value;
+ }
+}
+
+function unsupportedStartTransition() {
+ throw new Error('startTransition cannot be called during server rendering.');
+}
+
+function useTransition() {
+ resolveCurrentlyRenderingComponent();
+ return [false, unsupportedStartTransition];
+}
+
+function useHostTransitionStatus() {
+ resolveCurrentlyRenderingComponent();
+ return NotPendingTransition;
+}
+
+function unsupportedSetOptimisticState() {
+ throw new Error('Cannot update optimistic state while rendering.');
+}
+
+function useOptimistic(passthrough, reducer) {
+ resolveCurrentlyRenderingComponent();
+ return [passthrough, unsupportedSetOptimisticState];
+}
+
+function createPostbackFormStateKey(permalink, componentKeyPath, hookIndex) {
+ if (permalink !== undefined) {
+ // Don't bother to hash a permalink-based key since it's already short.
+ return 'p' + permalink;
+ } else {
+ // Append a node to the key path that represents the form state hook.
+ const keyPath = [componentKeyPath, null, hookIndex]; // Key paths are hashed to reduce the size. It does not need to be secure,
+ // and it's more important that it's fast than that it's completely
+ // collision-free.
+
+ const keyPathHash = createFastHashJS(JSON.stringify(keyPath));
+ return 'k' + keyPathHash;
+ }
+}
+
+function useFormState(action, initialState, permalink) {
+ resolveCurrentlyRenderingComponent(); // Count the number of useFormState hooks per component. We also use this to
+ // track the position of this useFormState hook relative to the other ones in
+ // this component, so we can generate a unique key for each one.
+
+ const formStateHookIndex = formStateCounter++;
+ const request = currentlyRenderingRequest; // $FlowIgnore[prop-missing]
+
+ const formAction = action.$$FORM_ACTION;
+
+ if (typeof formAction === 'function') {
+ // This is a server action. These have additional features to enable
+ // MPA-style form submissions with progressive enhancement.
+ // TODO: If the same permalink is passed to multiple useFormStates, and
+ // they all have the same action signature, Fizz will pass the postback
+ // state to all of them. We should probably only pass it to the first one,
+ // and/or warn.
+ // The key is lazily generated and deduped so the that the keypath doesn't
+ // get JSON.stringify-ed unnecessarily, and at most once.
+ let nextPostbackStateKey = null; // Determine the current form state. If we received state during an MPA form
+ // submission, then we will reuse that, if the action identity matches.
+ // Otherwise we'll use the initial state argument. We will emit a comment
+ // marker into the stream that indicates whether the state was reused.
+
+ let state = initialState;
+ const componentKeyPath = currentlyRenderingKeyPath;
+ const postbackFormState = getFormState(request); // $FlowIgnore[prop-missing]
+
+ const isSignatureEqual = action.$$IS_SIGNATURE_EQUAL;
+
+ if (postbackFormState !== null && typeof isSignatureEqual === 'function') {
+ const postbackKey = postbackFormState[1];
+ const postbackReferenceId = postbackFormState[2];
+ const postbackBoundArity = postbackFormState[3];
+
+ if (isSignatureEqual.call(action, postbackReferenceId, postbackBoundArity)) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+
+ if (postbackKey === nextPostbackStateKey) {
+ // This was a match
+ formStateMatchingIndex = formStateHookIndex; // Reuse the state that was submitted by the form.
+
+ state = postbackFormState[0];
+ }
+ }
+ } // Bind the state to the first argument of the action.
+
+
+ const boundAction = action.bind(null, state); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ }; // $FlowIgnore[prop-missing]
+
+
+ if (typeof boundAction.$$FORM_ACTION === 'function') {
+ // $FlowIgnore[prop-missing]
+ dispatch.$$FORM_ACTION = prefix => {
+ const metadata = boundAction.$$FORM_ACTION(prefix); // Override the action URL
+
+ if (permalink !== undefined) {
+
+ permalink += '';
+ metadata.action = permalink;
+ }
+
+ const formData = metadata.data;
+
+ if (formData) {
+ if (nextPostbackStateKey === null) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+ }
+
+ formData.append('$ACTION_KEY', nextPostbackStateKey);
+ }
+
+ return metadata;
+ };
+ }
+
+ return [state, dispatch];
+ } else {
+ // This is not a server action, so the implementation is much simpler.
+ // Bind the state to the first argument of the action.
+ const boundAction = action.bind(null, initialState); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ };
+
+ return [initialState, dispatch];
+ }
+}
+
+function useId() {
+ const task = currentlyRenderingTask;
+ const treeId = getTreeId(task.treeContext);
+ const resumableState = currentResumableState;
+
+ if (resumableState === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component.');
+ }
+
+ const localId = localIdCounter++;
+ return makeId(resumableState, treeId, localId);
+}
+
+function use(usable) {
+ if (usable !== null && typeof usable === 'object') {
+ // $FlowFixMe[method-unbinding]
+ if (typeof usable.then === 'function') {
+ // This is a thenable.
+ const thenable = usable;
+ return unwrapThenable(thenable);
+ } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = usable;
+ return readContext(context);
+ }
+ } // eslint-disable-next-line react-internal/safe-string-coercion
+
+
+ throw new Error('An unsupported type was passed to use(): ' + String(usable));
+}
+
+function unwrapThenable(thenable) {
+ const index = thenableIndexCounter;
+ thenableIndexCounter += 1;
+
+ if (thenableState === null) {
+ thenableState = createThenableState();
+ }
+
+ return trackUsedThenable(thenableState, thenable, index);
+}
+
+function unsupportedRefresh() {
+ throw new Error('Cache cannot be refreshed during server rendering.');
+}
+
+function useCacheRefresh() {
+ return unsupportedRefresh;
+}
+
+function noop$1() {}
+
+const HooksDispatcher = {
+ readContext,
+ use,
+ useContext,
+ useMemo,
+ useReducer,
+ useRef,
+ useState,
+ useInsertionEffect: noop$1,
+ useLayoutEffect: noop$1,
+ useCallback,
+ // useImperativeHandle is not run in the server environment
+ useImperativeHandle: noop$1,
+ // Effects are not run in the server environment.
+ useEffect: noop$1,
+ // Debugging effect
+ useDebugValue: noop$1,
+ useDeferredValue,
+ useTransition,
+ useId,
+ // Subscriptions are not setup in a server environment.
+ useSyncExternalStore
+};
+
+{
+ HooksDispatcher.useCacheRefresh = useCacheRefresh;
+}
+
+{
+ HooksDispatcher.useHostTransitionStatus = useHostTransitionStatus;
+}
+
+{
+ HooksDispatcher.useOptimistic = useOptimistic;
+ HooksDispatcher.useFormState = useFormState;
+}
+
+let currentResumableState = null;
+function setCurrentResumableState(resumableState) {
+ currentResumableState = resumableState;
+}
+
+function getCacheSignal() {
+ throw new Error('Not implemented.');
+}
+
+function getCacheForType(resourceType) {
+ throw new Error('Not implemented.');
+}
+
+const DefaultCacheDispatcher = {
+ getCacheSignal,
+ getCacheForType
+};
+
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
+const ReactCurrentCache = ReactSharedInternals.ReactCurrentCache;
+// The name might be minified but we assume that it's going to be the same generated name. Typically
+// because it's just the same compiled output in practice.
+// resume with segmentID at the index
+
+const CLIENT_RENDERED = 4; // if it errors or infinitely suspends
+
+const PENDING = 0;
+const COMPLETED = 1;
+const FLUSHED = 2;
+const ABORTED = 3;
+const ERRORED = 4;
+const POSTPONED = 5;
+const OPEN = 0;
+const CLOSING = 1;
+const CLOSED = 2; // This is a default heuristic for how to split up the HTML content into progressive
+// loading. Our goal is to be able to display additional new content about every 500ms.
+// Faster than that is unnecessary and should be throttled on the client. It also
+// adds unnecessary overhead to do more splits. We don't know if it's a higher or lower
+// end device but higher end suffer less from the overhead than lower end does from
+// not getting small enough pieces. We error on the side of low end.
+// We base this on low end 3G speeds which is about 500kbits per second. We assume
+// that there can be a reasonable drop off from max bandwidth which leaves you with
+// as little as 80%. We can receive half of that each 500ms - at best. In practice,
+// a little bandwidth is lost to processing and contention - e.g. CSS and images that
+// are downloaded along with the main content. So we estimate about half of that to be
+// the lower end throughput. In other words, we expect that you can at least show
+// about 12.5kb of content per 500ms. Not counting starting latency for the first
+// paint.
+// 500 * 1024 / 8 * .8 * 0.5 / 2
+
+const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
+
+function defaultErrorHandler(error) {
+ console['error'](error); // Don't transform to our wrapper
+
+ return null;
+}
+
+function noop() {}
+
+function createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, formState) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState,
+ renderState,
+ rootFormatContext,
+ progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: 0,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: formState === undefined ? null : formState
+ }; // This segment represents the root fallback.
+
+ const rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false); // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+let currentRequest = null;
+function resolveRequest() {
+ if (currentRequest) return currentRequest;
+
+ return null;
+}
+
+function pingTask(request, task) {
+ const pingedTasks = request.pingedTasks;
+ pingedTasks.push(task);
+
+ if (request.pingedTasks.length === 1) {
+ request.flushScheduled = request.destination !== null;
+ scheduleWork(() => performWork(request));
+ }
+}
+
+function createSuspenseBoundary(request, fallbackAbortableTasks) {
+ return {
+ status: PENDING,
+ rootSegmentID: -1,
+ parentFlushed: false,
+ pendingTasks: 0,
+ completedSegments: [],
+ byteSize: 0,
+ fallbackAbortableTasks,
+ errorDigest: null,
+ resources: createBoundaryResources(),
+ trackedContentKeyPath: null,
+ trackedFallbackNode: null
+ };
+}
+
+function createRenderTask(request, thenableState, node, childIndex, blockedBoundary, blockedSegment, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ const task = {
+ replay: null,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createReplayTask(request, thenableState, replay, node, childIndex, blockedBoundary, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ replay.pendingTasks++;
+ const task = {
+ replay,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment: null,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createPendingSegment(request, index, boundary, parentFormatContext, lastPushedText, textEmbedded) {
+ return {
+ status: PENDING,
+ id: -1,
+ // lazily assigned later
+ index,
+ parentFlushed: false,
+ chunks: [],
+ children: [],
+ parentFormatContext,
+ boundary,
+ lastPushedText,
+ textEmbedded
+ };
+} // DEV-only global reference to the currently executing task
+
+function popComponentStackInDEV(task) {
+} // stash the component stack of an unwinding error until it is processed
+
+function logRecoverableError(request, error) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ const errorDigest = request.onError(error);
+
+ if (errorDigest != null && typeof errorDigest !== 'string') {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead");
+ }
+
+ return errorDigest;
+}
+
+function fatalError(request, error) {
+ // This is called outside error handling code such as if the root errors outside
+ // a suspense boundary or if the root suspense boundary's fallback errors.
+ // It's also called if React itself or its host configs errors.
+ const onShellError = request.onShellError;
+ onShellError(error);
+ const onFatalError = request.onFatalError;
+ onFatalError(error);
+
+ if (request.destination !== null) {
+ request.status = CLOSED;
+ closeWithError(request.destination, error);
+ } else {
+ request.status = CLOSING;
+ request.fatalError = error;
+ }
+}
+
+function renderSuspenseBoundary(request, someTask, keyPath, props) {
+ if (someTask.replay !== null) {
+ // If we're replaying through this pass, it means we're replaying through
+ // an already completed Suspense boundary. It's too late to do anything about it
+ // so we can just render through it.
+ const prevKeyPath = someTask.keyPath;
+ someTask.keyPath = keyPath;
+ const content = props.children;
+
+ try {
+ renderNode(request, someTask, content, -1);
+ } finally {
+ someTask.keyPath = prevKeyPath;
+ }
+
+ return;
+ } // $FlowFixMe: Refined.
+
+
+ const task = someTask;
+ const prevKeyPath = task.keyPath;
+ const parentBoundary = task.blockedBoundary;
+ const parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for
+ // the fallback so that we can later replace that segment with the content.
+ // This also lets us split out the main content even if it doesn't suspend,
+ // in case it ends up generating a large subtree of content.
+
+ const fallback = props.fallback;
+ const content = props.children;
+ const fallbackAbortSet = new Set();
+ const newBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+
+ if (request.trackedPostpones !== null) {
+ newBoundary.trackedContentKeyPath = keyPath;
+ }
+
+ const insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback.
+
+ const boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false);
+ parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent
+
+ parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately.
+
+ const contentRootSegment = createPendingSegment(request, 0, null, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is
+ // no parent segment so there's nothing to wait on.
+
+ contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks.
+ // I suspect that there might be some efficiency benefits from not creating the suspended task
+ // and instead just using the stack if possible.
+ // TODO: Call this directly instead of messing with saving and restoring contexts.
+ // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and which segment
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = newBoundary;
+ task.blockedSegment = contentRootSegment;
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, newBoundary.resources);
+ }
+
+ task.keyPath = keyPath;
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+ pushSegmentFinale(contentRootSegment.chunks, request.renderState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded);
+ contentRootSegment.status = COMPLETED;
+ queueCompletedSegment(newBoundary, contentRootSegment);
+
+ if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
+ newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ contentRootSegment.status = ERRORED;
+ newBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ newBoundary.errorDigest = errorDigest;
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.blockedSegment = parentSegment;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]];
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones !== null) {
+ // We create a detached replay node to track any postpones inside the fallback.
+ const fallbackReplayNode = [fallbackKeyPath[1], fallbackKeyPath[2], [], null];
+ trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
+
+ if (newBoundary.status === POSTPONED) {
+ // This must exist now.
+ const boundaryReplayNode = trackedPostpones.workingMap.get(keyPath);
+ boundaryReplayNode[4] = fallbackReplayNode;
+ } else {
+ // We might not inject it into the postponed tree, unless the content actually
+ // postpones too. We need to keep track of it until that happpens.
+ newBoundary.trackedFallbackNode = fallbackReplayNode;
+ }
+ } // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+
+ const suspendedFallbackTask = createRenderTask(request, null, fallback, -1, parentBoundary, boundarySegment, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function replaySuspenseBoundary(request, task, keyPath, props, id, childNodes, childSlots, fallbackNodes, fallbackSlots) {
+ const prevKeyPath = task.keyPath;
+ const previousReplaySet = task.replay;
+ const parentBoundary = task.blockedBoundary;
+ const content = props.children;
+ const fallback = props.fallback;
+ const fallbackAbortSet = new Set();
+ const resumedBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = id; // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and replay node
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = resumedBoundary;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, resumedBoundary.resources);
+ }
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+
+ if (resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING) {
+ resumedBoundary.status = COMPLETED;
+ request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ resumedBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ resumedBoundary.errorDigest = errorDigest;
+
+ task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted.
+
+ request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task.
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.replay = previousReplaySet;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+ const fallbackReplay = {
+ nodes: fallbackNodes,
+ slots: fallbackSlots,
+ pendingTasks: 0
+ };
+ const suspendedFallbackTask = createReplayTask(request, null, fallbackReplay, fallback, -1, parentBoundary, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function renderHostElement(request, task, keyPath, type, props) {
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ const children = props.children; // TODO: Make this a Config for replaying.
+
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ } else {
+ // Render
+ const children = pushStartInstance(segment.chunks, type, props, request.resumableState, request.renderState, task.formatContext, segment.lastPushedText);
+ segment.lastPushedText = false;
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ pushEndInstance(segment.chunks, type, props, request.resumableState, prevContext);
+ segment.lastPushedText = false;
+ }
+}
+
+function shouldConstruct(Component) {
+ return Component.prototype && Component.prototype.isReactComponent;
+}
+
+function renderWithHooks(request, task, keyPath, prevThenableState, Component, props, secondArg) {
+ const componentIdentity = {};
+ prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState);
+ const result = Component(props, secondArg);
+ return finishHooks(Component, props, result, secondArg);
+}
+
+function finishClassComponent(request, task, keyPath, instance, Component, props) {
+ const nextChildren = instance.render();
+
+ {
+ const childContextTypes = Component.childContextTypes;
+
+ if (childContextTypes !== null && childContextTypes !== undefined) {
+ const previousContext = task.legacyContext;
+ const mergedContext = processChildContext(instance, Component, previousContext, childContextTypes);
+ task.legacyContext = mergedContext;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.legacyContext = previousContext;
+ return;
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderClassComponent(request, task, keyPath, Component, props) {
+ const maskedContext = getMaskedContext(Component, task.legacyContext) ;
+ const instance = constructClassInstance(Component, props, maskedContext);
+ mountClassInstance(instance, Component, props, maskedContext);
+ finishClassComponent(request, task, keyPath, instance, Component);
+}
+// components for some reason.
+
+function renderIndeterminateComponent(request, task, keyPath, prevThenableState, Component, props) {
+ let legacyContext;
+
+ {
+ legacyContext = getMaskedContext(Component, task.legacyContext);
+ }
+
+ const value = renderWithHooks(request, task, keyPath, prevThenableState, Component, props, legacyContext);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+
+ if ( // Run these checks in production only if the flag is off.
+ // Eventually we'll delete this branch altogether.
+ typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
+
+ mountClassInstance(value, Component, props, legacyContext);
+ finishClassComponent(request, task, keyPath, value, Component);
+ } else {
+
+ finishFunctionComponent(request, task, keyPath, value, hasId, formStateCount, formStateMatchingIndex);
+ }
+}
+
+function finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex) {
+ let didEmitFormStateMarkers = false;
+
+ if (formStateCount !== 0 && request.formState !== null) {
+ // For each useFormState hook, emit a marker that indicates whether we
+ // rendered using the form state passed at the root. We only emit these
+ // markers if form state is passed at the root.
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ didEmitFormStateMarkers = true;
+ const target = segment.chunks;
+
+ for (let i = 0; i < formStateCount; i++) {
+ if (i === formStateMatchingIndex) {
+ pushFormStateMarkerIsMatching(target);
+ } else {
+ pushFormStateMarkerIsNotMatching(target);
+ }
+ }
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+
+ if (hasId) {
+ // This component materialized an id. We treat this as its own level, with
+ // a single "child" slot.
+ const prevTreeContext = task.treeContext;
+ const totalChildren = 1;
+ const index = 0; // Modify the id context. Because we'll need to reset this if something
+ // suspends or errors, we'll use the non-destructive render path.
+
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
+ renderNode(request, task, children, -1); // Like the other contexts, this does not need to be in a finally block
+ // because renderNode takes care of unwinding the stack.
+
+ task.treeContext = prevTreeContext;
+ } else if (didEmitFormStateMarkers) {
+ // If there were formState hooks, we must use the non-destructive path
+ // because this component is not a pure indirection; we emitted markers
+ // to the stream.
+ renderNode(request, task, children, -1);
+ } else {
+ // We're now successfully past this task, and we haven't modified the
+ // context stack. We don't have to pop back to the previous task every
+ // again, so we can use the destructive recursive form.
+ renderNodeDestructive(request, task, null, children, -1);
+ }
+
+ task.keyPath = prevKeyPath;
+}
+
+function resolveDefaultProps(Component, baseProps) {
+ if (Component && Component.defaultProps) {
+ // Resolve default props. Taken from ReactElement
+ const props = assign({}, baseProps);
+ const defaultProps = Component.defaultProps;
+
+ for (const propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+
+ return props;
+ }
+
+ return baseProps;
+}
+
+function renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref) {
+ const children = renderWithHooks(request, task, keyPath, prevThenableState, type.render, props, ref);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+ finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex);
+}
+
+function renderMemo(request, task, keyPath, prevThenableState, type, props, ref) {
+ const innerType = type.type;
+ const resolvedProps = resolveDefaultProps(innerType, props);
+ renderElement(request, task, keyPath, prevThenableState, innerType, resolvedProps, ref);
+}
+
+function renderContextConsumer(request, task, keyPath, context, props) {
+
+ const render = props.children;
+
+ const newValue = readContext$1(context);
+ const newChildren = render(newValue);
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, newChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderContextProvider(request, task, keyPath, type, props) {
+ const context = type._context;
+ const value = props.value;
+ const children = props.children;
+
+ const prevKeyPath = task.keyPath;
+ task.context = pushProvider(context, value);
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, children, -1);
+ task.context = popProvider();
+ task.keyPath = prevKeyPath;
+}
+
+function renderLazyComponent(request, task, keyPath, prevThenableState, lazyComponent, props, ref) {
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+ const Component = init(payload);
+ const resolvedProps = resolveDefaultProps(Component, props);
+ renderElement(request, task, keyPath, prevThenableState, Component, resolvedProps, ref);
+}
+
+function renderOffscreen(request, task, keyPath, props) {
+ const mode = props.mode;
+
+ if (mode === 'hidden') ; else {
+ // A visible Offscreen boundary is treated exactly like a fragment: a
+ // pure indirection.
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ }
+}
+
+function renderElement(request, task, keyPath, prevThenableState, type, props, ref) {
+ if (typeof type === 'function') {
+ if (shouldConstruct(type)) {
+ renderClassComponent(request, task, keyPath, type, props);
+ return;
+ } else {
+ renderIndeterminateComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+
+ if (typeof type === 'string') {
+ renderHostElement(request, task, keyPath, type, props);
+ return;
+ }
+
+ switch (type) {
+ // LegacyHidden acts the same as a fragment. This only works because we
+ // currently assume that every instance of LegacyHidden is accompanied by a
+ // host component wrapper. In the hidden mode, the host component is given a
+ // `hidden` attribute, which ensures that the initial HTML is not visible.
+ // To support the use of LegacyHidden as a true fragment, without an extra
+ // DOM node, we would have to hide the initial HTML in some other way.
+ // TODO: Delete in LegacyHidden. It's an unstable API only used in the
+ // www build. As a migration step, we could add a special prop to Offscreen
+ // that simulates the old behavior (no hiding, no change to effects).
+ case REACT_LEGACY_HIDDEN_TYPE:
+ case REACT_DEBUG_TRACING_MODE_TYPE:
+ case REACT_STRICT_MODE_TYPE:
+ case REACT_PROFILER_TYPE:
+ case REACT_FRAGMENT_TYPE:
+ {
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_OFFSCREEN_TYPE:
+ {
+ renderOffscreen(request, task, keyPath, props);
+ return;
+ }
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ {
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_SCOPE_TYPE:
+ {
+
+ throw new Error('ReactDOMServer does not yet support scope components.');
+ }
+
+ case REACT_SUSPENSE_TYPE:
+ {
+ {
+ renderSuspenseBoundary(request, task, keyPath, props);
+ }
+
+ return;
+ }
+ }
+
+ if (typeof type === 'object' && type !== null) {
+ switch (type.$$typeof) {
+ case REACT_FORWARD_REF_TYPE:
+ {
+ renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_MEMO_TYPE:
+ {
+ renderMemo(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_PROVIDER_TYPE:
+ {
+ renderContextProvider(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_CONTEXT_TYPE:
+ {
+ renderContextConsumer(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_LAZY_TYPE:
+ {
+ renderLazyComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+ }
+
+ let info = '';
+
+ throw new Error('Element type is invalid: expected a string (for built-in ' + 'components) or a class/function (for composite components) ' + ("but got: " + (type == null ? type : typeof type) + "." + info));
+}
+
+function resumeNode(request, task, segmentId, node, childIndex) {
+ const prevReplay = task.replay;
+ const blockedBoundary = task.blockedBoundary;
+ const resumedSegment = createPendingSegment(request, 0, null, task.formatContext, false, false);
+ resumedSegment.id = segmentId;
+ resumedSegment.parentFlushed = true;
+
+ try {
+ // Convert the current ReplayTask to a RenderTask.
+ const renderTask = task;
+ renderTask.replay = null;
+ renderTask.blockedSegment = resumedSegment;
+ renderNode(request, task, node, childIndex);
+ resumedSegment.status = COMPLETED;
+
+ if (blockedBoundary === null) {
+ request.completedRootSegment = resumedSegment;
+ } else {
+ queueCompletedSegment(blockedBoundary, resumedSegment);
+
+ if (blockedBoundary.parentFlushed) {
+ request.partialBoundaries.push(blockedBoundary);
+ }
+ }
+ } finally {
+ // Restore to a ReplayTask.
+ task.replay = prevReplay;
+ task.blockedSegment = null;
+ }
+}
+
+function replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, replay) {
+ // We're replaying. Find the path to follow.
+ const replayNodes = replay.nodes;
+
+ for (let i = 0; i < replayNodes.length; i++) {
+ // Flow doesn't support refinement on tuples so we do it manually here.
+ const node = replayNodes[i];
+
+ if (keyOrIndex !== node[1]) {
+ continue;
+ }
+
+ if (node.length === 4) {
+ // Matched a replayable path.
+ // Let's double check that the component name matches as a precaution.
+ if (name !== null && name !== node[0]) {
+ throw new Error('Expected the resume to render <' + node[0] + '> in this slot but instead it rendered <' + name + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ const currentNode = task.node;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0 // TODO check remaining slots
+ ) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ if (task.node === currentNode) {
+ // This same element suspended so we need to pop the replay we just added.
+ task.replay = replay;
+ }
+
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay;
+ } else {
+ // Let's double check that the component type matches.
+ if (type !== REACT_SUSPENSE_TYPE) {
+ const expectedType = 'Suspense';
+ throw new Error('Expected the resume to render <' + expectedType + '> in this slot but instead it rendered <' + (getComponentNameFromType(type) || 'Unknown') + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ } // Matched a replayable path.
+
+
+ replaySuspenseBoundary(request, task, keyPath, props, node[5], node[2], node[3], node[4] === null ? [] : node[4][2], node[4] === null ? null : node[4][3]);
+ } // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+
+ replayNodes.splice(i, 1);
+ return;
+ } // We didn't find any matching nodes. We assume that this element was already
+ // rendered in the prelude and skip it.
+
+} // $FlowFixMe[missing-local-annot]
+
+function renderNodeDestructive(request, task, // The thenable state reused from the previous attempt, if any. This is almost
+// always null, except when called by retryTask.
+prevThenableState, node, childIndex) {
+ {
+ return renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex);
+ }
+} // This function by it self renders a node and consumes the task by mutating it
+// to update the current execution state.
+
+
+function renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex) {
+ if (task.replay !== null && typeof task.replay.slots === 'number') {
+ // TODO: Figure out a cheaper place than this hot path to do this check.
+ const resumeSegmentID = task.replay.slots;
+ resumeNode(request, task, resumeSegmentID, node, childIndex);
+ return;
+ } // Stash the node we're working on. We'll pick up from this task in case
+ // something suspends.
+
+
+ task.node = node;
+ task.childIndex = childIndex; // Handle object types
+
+ if (typeof node === 'object' && node !== null) {
+ switch (node.$$typeof) {
+ case REACT_ELEMENT_TYPE:
+ {
+ const element = node;
+ const type = element.type;
+ const key = element.key;
+ const props = element.props;
+ const ref = element.ref;
+ const name = getComponentNameFromType(type);
+ const keyOrIndex = key == null ? childIndex === -1 ? 0 : childIndex : key;
+ const keyPath = [task.keyPath, name, keyOrIndex];
+
+ if (task.replay !== null) {
+ replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, task.replay); // No matches found for this node. We assume it's already emitted in the
+ // prelude and skip it during the replay.
+ } else {
+ // We're doing a plain render.
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+ }
+
+ return;
+ }
+
+ case REACT_PORTAL_TYPE:
+ throw new Error('Portals are not currently supported by the server renderer. ' + 'Render them conditionally so that they only appear on the client render.');
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyNode = node;
+ const payload = lazyNode._payload;
+ const init = lazyNode._init;
+ let resolvedNode;
+
+ {
+ resolvedNode = init(payload);
+ }
+
+ renderNodeDestructive(request, task, null, resolvedNode, childIndex);
+ return;
+ }
+ }
+
+ if (isArray(node)) {
+ renderChildrenArray(request, task, node, childIndex);
+ return;
+ }
+
+ const iteratorFn = getIteratorFn(node);
+
+ if (iteratorFn) {
+
+ const iterator = iteratorFn.call(node);
+
+ if (iterator) {
+ // We need to know how many total children are in this set, so that we
+ // can allocate enough id slots to acommodate them. So we must exhaust
+ // the iterator before we start recursively rendering the children.
+ // TODO: This is not great but I think it's inherent to the id
+ // generation algorithm.
+ let step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that.
+
+ if (!step.done) {
+ const children = [];
+
+ do {
+ children.push(step.value);
+ step = iterator.next();
+ } while (!step.done);
+
+ renderChildrenArray(request, task, children, childIndex);
+ return;
+ }
+
+ return;
+ }
+ } // Usables are a valid React node type. When React encounters a Usable in
+ // a child position, it unwraps it using the same algorithm as `use`. For
+ // example, for promises, React will throw an exception to unwind the
+ // stack, then replay the component once the promise resolves.
+ //
+ // A difference from `use` is that React will keep unwrapping the value
+ // until it reaches a non-Usable type.
+ //
+ // e.g. Usable>> should resolve to T
+
+
+ const maybeUsable = node;
+
+ if (typeof maybeUsable.then === 'function') {
+ const thenable = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable), childIndex);
+ }
+
+ if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, readContext$1(context), childIndex);
+ } // $FlowFixMe[method-unbinding]
+
+
+ const childString = Object.prototype.toString.call(node);
+ throw new Error("Objects are not valid as a React child (found: " + (childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString) + "). " + 'If you meant to render a collection of children, use an array ' + 'instead.');
+ }
+
+ if (typeof node === 'string') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+
+ if (typeof node === 'number') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, '' + node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+}
+
+function replayFragment(request, task, children, childIndex) {
+ // If we're supposed follow this array, we'd expect to see a ReplayNode matching
+ // this fragment.
+ const replay = task.replay;
+ const replayNodes = replay.nodes;
+
+ for (let j = 0; j < replayNodes.length; j++) {
+ const node = replayNodes[j];
+
+ if (node[1] !== childIndex) {
+ continue;
+ } // Matched a replayable path.
+
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderChildrenArray(request, task, children, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+ // This is an error, stash the component stack if it is null.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay; // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ replayNodes.splice(j, 1);
+ break;
+ }
+}
+
+function renderChildrenArray(request, task, children, childIndex) {
+ const prevKeyPath = task.keyPath;
+
+ if (childIndex !== -1) {
+ task.keyPath = [task.keyPath, 'Fragment', childIndex];
+
+ if (task.replay !== null) {
+ replayFragment(request, // $FlowFixMe: Refined.
+ task, children, childIndex);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ const prevTreeContext = task.treeContext;
+ const totalChildren = children.length;
+
+ if (task.replay !== null) {
+ // Replay
+ // First we need to check if we have any resume slots at this level.
+ const resumeSlots = task.replay.slots;
+
+ if (resumeSlots !== null && typeof resumeSlots === 'object') {
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ const resumeSegmentID = resumeSlots[i]; // TODO: If this errors we should still continue with the next sibling.
+
+ if (typeof resumeSegmentID === 'number') {
+ resumeNode(request, task, resumeSegmentID, node, i); // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ delete resumeSlots[i];
+ } else {
+ renderNode(request, task, node, i);
+ }
+ }
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ renderNode(request, task, node, i);
+ } // Because this context is always set right before rendering every child, we
+ // only need to reset it to the previous value at the very end.
+
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+}
+
+function spawnNewSuspendedReplayTask(request, task, thenableState, x) {
+ const newTask = createReplayTask(request, thenableState, task.replay, task.node, task.childIndex, task.blockedBoundary, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+}
+
+function spawnNewSuspendedRenderTask(request, task, thenableState, x) {
+ // Something suspended, we'll need to create a new segment and resolve it later.
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ const newTask = createRenderTask(request, thenableState, task.node, task.childIndex, task.blockedBoundary, newSegment, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+} // This is a non-destructive form of rendering a node. If it suspends it spawns
+// a new task and restores the context of this task to what it was before.
+
+
+function renderNode(request, task, node, childIndex) {
+ // Snapshot the current context in case something throws to interrupt the
+ // process.
+ const previousFormatContext = task.formatContext;
+ const previousLegacyContext = task.legacyContext;
+ const previousContext = task.context;
+ const previousKeyPath = task.keyPath;
+ const previousTreeContext = task.treeContext;
+
+ let x; // Store how much we've pushed at this point so we can reset it in case something
+ // suspended partially through writing something.
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState();
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedReplayTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode.
+
+ }
+ } else {
+ // Render
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedRenderTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ }
+ }
+ } // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ // Let's terminate the rest of the tree and don't render any siblings.
+
+
+ throw x;
+}
+
+function erroredReplay(request, boundary, error, replayNodes, resumeSlots) {
+ // Erroring during a replay doesn't actually cause an error by itself because
+ // that component has already rendered. What causes the error is the resumable
+ // points that we did not yet finish which will be below the point of the reset.
+ // For example, if we're replaying a path to a Suspense boundary that is not done
+ // that doesn't error the parent Suspense boundary.
+ // This might be a bit strange that the error in a parent gets thrown at a child.
+ // We log it only once and reuse the digest.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ abortRemainingReplayNodes(request, boundary, replayNodes, resumeSlots, error, errorDigest);
+}
+
+function erroredTask(request, boundary, error) {
+ // Report the error to a global handler.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ if (boundary === null) {
+ fatalError(request, error);
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+ // so we can flush it, if the parent already flushed.
+
+
+ if (boundary.parentFlushed) {
+ // We don't have a preference where in the queue this goes since it's likely
+ // to error on the client anyway. However, intentionally client-rendered
+ // boundaries should be flushed earlier so that they can start on the client.
+ // We reuse the same queue for errors.
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function abortTaskSoft(task) {
+ // This aborts task without aborting the parent boundary that it blocks.
+ // It's used for when we didn't need this task to complete the tree.
+ // If task was needed, then it should use abortTask instead.
+ const request = this;
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ finishedTask(request, boundary, segment);
+ }
+}
+
+function abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest) {
+ const resumedBoundary = createSuspenseBoundary(request, new Set());
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = rootSegmentID;
+ resumedBoundary.status = CLIENT_RENDERED;
+ resumedBoundary.errorDigest = errorDigest;
+
+ if (resumedBoundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(resumedBoundary);
+ }
+}
+
+function abortRemainingReplayNodes(request, boundary, nodes, slots, error, errorDigest) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+
+ if (node.length === 4) {
+ abortRemainingReplayNodes(request, boundary, node[2], node[3], error, errorDigest);
+ } else {
+ const boundaryNode = node;
+ const rootSegmentID = boundaryNode[5];
+ abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest);
+ }
+ } // Empty the set, since we've cleared it now.
+
+
+ nodes.length = 0;
+
+ if (slots !== null) {
+ // We had something still to resume in the parent boundary. We must trigger
+ // the error on the parent boundary since it's not able to complete.
+ if (boundary === null) {
+ throw new Error('We should not have any resumable nodes in the shell. ' + 'This is a bug in React.');
+ } else if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // Empty the set
+
+
+ if (typeof slots === 'object') {
+ for (const index in slots) {
+ delete slots[index];
+ }
+ }
+ }
+}
+
+function abortTask(task, request, error) {
+ // This aborts the task and aborts the parent that it blocks, putting it into
+ // client rendered mode.
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ }
+
+ if (boundary === null) {
+ if (request.status !== CLOSING && request.status !== CLOSED) {
+ const replay = task.replay;
+
+ if (replay === null) {
+ // We didn't complete the root so we have nothing to show. We can close
+ // the request;
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ return;
+ } else {
+ // If the shell aborts during a replay, that's not a fatal error. Instead
+ // we should be able to recover by client rendering all the root boundaries in
+ // the ReplaySet.
+ replay.pendingTasks--;
+
+ if (replay.pendingTasks === 0 && replay.nodes.length > 0) {
+ const errorDigest = logRecoverableError(request, error);
+ abortRemainingReplayNodes(request, null, replay.nodes, replay.slots, error, errorDigest);
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ }
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = logRecoverableError(request, error);
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // If this boundary was still pending then we haven't already cancelled its fallbacks.
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
+
+
+ boundary.fallbackAbortableTasks.forEach(fallbackTask => abortTask(fallbackTask, request, error));
+ boundary.fallbackAbortableTasks.clear();
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeShell(request) {
+ if (request.trackedPostpones === null) {
+ // We only emit early preloads on shell completion for renders. For prerenders
+ // we wait for the entire Request to finish because we are not responding to a
+ // live request and can wait for as much data as possible.
+ // we should only be calling completeShell when the shell is complete so we
+ // just use a literal here
+ const shellComplete = true;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ } // We have completed the shell so the shell can't error anymore.
+
+
+ request.onShellError = noop;
+ const onShellReady = request.onShellReady;
+ onShellReady();
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeAll(request) {
+ // During a render the shell must be complete if the entire request is finished
+ // however during a Prerender it is possible that the shell is incomplete because
+ // it postponed. We cannot use rootPendingTasks in the prerender case because
+ // those hit zero even when the shell postpones. Instead we look at the completedRootSegment
+ const shellComplete = request.trackedPostpones === null ? // Render, we assume it is completed
+ true : // Prerender Request, we use the state of the root segment
+ request.completedRootSegment === null || request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ const onAllReady = request.onAllReady;
+ onAllReady();
+}
+
+function queueCompletedSegment(boundary, segment) {
+ if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) {
+ // This is an empty segment. There's nothing to write, so we can instead transfer the ID
+ // to the child. That way any existing references point to the child.
+ const childSegment = segment.children[0];
+ childSegment.id = segment.id;
+ childSegment.parentFlushed = true;
+
+ if (childSegment.status === COMPLETED) {
+ queueCompletedSegment(boundary, childSegment);
+ }
+ } else {
+ const completedSegments = boundary.completedSegments;
+ completedSegments.push(segment);
+ }
+}
+
+function finishedTask(request, boundary, segment) {
+ if (boundary === null) {
+ if (segment !== null && segment.parentFlushed) {
+ if (request.completedRootSegment !== null) {
+ throw new Error('There can only be one root segment. This is a bug in React.');
+ }
+
+ request.completedRootSegment = segment;
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status === CLIENT_RENDERED) ; else if (boundary.pendingTasks === 0) {
+ if (boundary.status === PENDING) {
+ boundary.status = COMPLETED;
+ } // This must have been the last segment we were waiting on. This boundary is now complete.
+
+
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent segment already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ }
+ }
+
+ if (boundary.parentFlushed) {
+ // The segment might be part of a segment that didn't flush yet, but if the boundary's
+ // parent flushed, we need to schedule the boundary to be emitted.
+ request.completedBoundaries.push(boundary);
+ } // We can now cancel any pending task on the fallback since we won't need to show it anymore.
+ // This needs to happen after we read the parentFlushed flags because aborting can finish
+ // work which can trigger user code, which can start flushing, which can change those flags.
+ // If the boundary was POSTPONED, we still need to finish the fallback first.
+
+
+ if (boundary.status === COMPLETED) {
+ boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
+ boundary.fallbackAbortableTasks.clear();
+ }
+ } else {
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length === 1) {
+ // This is the first time since we last flushed that we completed anything.
+ // We can schedule this boundary to emit its partially completed segments early
+ // in case the parent has already been flushed.
+ if (boundary.parentFlushed) {
+ request.partialBoundaries.push(boundary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function retryTask(request, task) {
+ {
+ const blockedBoundary = task.blockedBoundary;
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, blockedBoundary ? blockedBoundary.resources : null);
+ }
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ retryReplayTask(request, // $FlowFixMe: Refined.
+ task);
+ } else {
+ retryRenderTask(request, // $FlowFixMe: Refined.
+ task, segment);
+ }
+}
+
+function retryRenderTask(request, task, segment) {
+ if (segment.status !== PENDING) {
+ // We completed this by other means before we had a chance to retry it.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+ pushSegmentFinale(segment.chunks, request.renderState, segment.lastPushedText, segment.textEmbedded);
+ task.abortSet.delete(task);
+ segment.status = COMPLETED;
+ finishedTask(request, task.blockedBoundary, segment);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.abortSet.delete(task);
+ segment.status = ERRORED;
+ erroredTask(request, task.blockedBoundary, x);
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function retryReplayTask(request, task) {
+ if (task.replay.pendingTasks === 0) {
+ // There are no pending tasks working on this set, so we must have aborted.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ finishedTask(request, task.blockedBoundary, null);
+ } catch (thrownValue) {
+ resetHooksState();
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ erroredReplay(request, task.blockedBoundary, x, task.replay.nodes, task.replay.slots);
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function performWork(request) {
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ const prevContext = getActiveContext();
+ const prevDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = HooksDispatcher;
+ let prevCacheDispatcher;
+
+ {
+ prevCacheDispatcher = ReactCurrentCache.current;
+ ReactCurrentCache.current = DefaultCacheDispatcher;
+ }
+
+ const prevRequest = currentRequest;
+ currentRequest = request;
+
+ const prevResumableState = currentResumableState;
+ setCurrentResumableState(request.resumableState);
+
+ try {
+ const pingedTasks = request.pingedTasks;
+ let i;
+
+ for (i = 0; i < pingedTasks.length; i++) {
+ const task = pingedTasks[i];
+ retryTask(request, task);
+ }
+
+ pingedTasks.splice(0, i);
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ } finally {
+ setCurrentResumableState(prevResumableState);
+ ReactCurrentDispatcher.current = prevDispatcher;
+
+ {
+ ReactCurrentCache.current = prevCacheDispatcher;
+ }
+
+ if (prevDispatcher === HooksDispatcher) {
+ // This means that we were in a reentrant work loop. This could happen
+ // in a renderer that supports synchronous work like renderToString,
+ // when it's called from within another renderer.
+ // Normally we don't bother switching the contexts to their root/default
+ // values when leaving because we'll likely need the same or similar
+ // context again. However, when we're inside a synchronous loop like this
+ // we'll to restore the context to what it was before returning.
+ switchContext(prevContext);
+ }
+
+ currentRequest = prevRequest;
+ }
+}
+
+function flushSubtree(request, destination, segment) {
+ segment.parentFlushed = true;
+
+ switch (segment.status) {
+ case PENDING:
+ {
+ // We're emitting a placeholder for this segment to be filled in later.
+ // Therefore we'll need to assign it an ID - to refer to it by.
+ segment.id = request.nextSegmentId++; // Fallthrough
+ }
+
+ case POSTPONED:
+ {
+ const segmentID = segment.id; // When this segment finally completes it won't be embedded in text since it will flush separately
+
+ segment.lastPushedText = false;
+ segment.textEmbedded = false;
+ return writePlaceholder(destination, request.renderState, segmentID);
+ }
+
+ case COMPLETED:
+ {
+ segment.status = FLUSHED;
+ let r = true;
+ const chunks = segment.chunks;
+ let chunkIdx = 0;
+ const children = segment.children;
+
+ for (let childIdx = 0; childIdx < children.length; childIdx++) {
+ const nextChild = children[childIdx]; // Write all the chunks up until the next child.
+
+ for (; chunkIdx < nextChild.index; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ r = flushSegment(request, destination, nextChild);
+ } // Finally just write all the remaining chunks
+
+
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ if (chunkIdx < chunks.length) {
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
+ }
+
+ return r;
+ }
+
+ default:
+ {
+ throw new Error('Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.');
+ }
+ }
+}
+
+function flushSegment(request, destination, segment) {
+ const boundary = segment.boundary;
+
+ if (boundary === null) {
+ // Not a suspense boundary.
+ return flushSubtree(request, destination, segment);
+ }
+
+ boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to
+ // emit the content or the fallback now.
+
+ if (boundary.status === CLIENT_RENDERED) {
+ // Emit a client rendered suspense boundary wrapper.
+ // We never queue the inner boundary so we'll never emit its content or partial segments.
+ writeStartClientRenderedSuspenseBoundary(destination, request.renderState, boundary.errorDigest); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndClientRenderedSuspenseBoundary(destination, request.renderState);
+ } else if (boundary.status !== COMPLETED) {
+ if (boundary.status === PENDING) {
+ // For pending boundaries we lazily assign an ID to the boundary
+ // and root segment.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ }
+
+ if (boundary.completedSegments.length > 0) {
+ // If this is at least partially complete, we can queue it to be partially emitted early.
+ request.partialBoundaries.push(boundary);
+ } // This boundary is still loading. Emit a pending suspense boundary wrapper.
+
+
+ const id = boundary.rootSegmentID;
+ writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else if (boundary.byteSize > request.progressiveChunkSize) {
+ // This boundary is large and will be emitted separately so that we can progressively show
+ // other content. We add it to the queue during the flush because we have to ensure that
+ // the parent flushes first so that there's something to inject it into.
+ // We also have to make sure that it's emitted into the queue in a deterministic slot.
+ // I.e. we can't insert it here when it completes.
+ // Assign an ID to refer to the future content by.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper.
+
+ writeStartPendingSuspenseBoundary(destination, request.renderState, boundary.rootSegmentID); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else {
+ {
+ hoistResources(request.renderState, boundary.resources);
+ } // We can inline this boundary's content as a complete boundary.
+
+
+ writeStartCompletedSuspenseBoundary(destination, request.renderState);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length !== 1) {
+ throw new Error('A previously unvisited boundary must have exactly one root segment. This is a bug in React.');
+ }
+
+ const contentSegment = completedSegments[0];
+ flushSegment(request, destination, contentSegment);
+ return writeEndCompletedSuspenseBoundary(destination, request.renderState);
+ }
+}
+
+function flushClientRenderedBoundary(request, destination, boundary) {
+ return writeClientRenderBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack);
+}
+
+function flushSegmentContainer(request, destination, segment) {
+ writeStartSegment(destination, request.renderState, segment.parentFormatContext, segment.id);
+ flushSegment(request, destination, segment);
+ return writeEndSegment(destination, segment.parentFormatContext);
+}
+
+function flushCompletedBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+ flushPartiallyCompletedSegment(request, destination, boundary, segment);
+ }
+
+ completedSegments.length = 0;
+
+ {
+ writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+
+ return writeCompletedBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.resources);
+}
+
+function flushPartialBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+
+ if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) {
+ i++;
+ completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority
+ // might want to write later.
+
+ return false;
+ }
+ }
+
+ completedSegments.splice(0, i);
+
+ {
+ // The way this is structured we only write resources for partial boundaries
+ // if there is no backpressure. Later before we complete the boundary we
+ // will write resources regardless of backpressure before we emit the
+ // completion instruction
+ return writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+}
+
+function flushPartiallyCompletedSegment(request, destination, boundary, segment) {
+ if (segment.status === FLUSHED) {
+ // We've already flushed this inline.
+ return true;
+ }
+
+ const segmentID = segment.id;
+
+ if (segmentID === -1) {
+ // This segment wasn't previously referred to. This happens at the root of
+ // a boundary. We make kind of a leap here and assume this is the root.
+ const rootSegmentID = segment.id = boundary.rootSegmentID;
+
+ if (rootSegmentID === -1) {
+ throw new Error('A root segment ID must have been assigned by now. This is a bug in React.');
+ }
+
+ return flushSegmentContainer(request, destination, segment);
+ } else if (segmentID === boundary.rootSegmentID) {
+ // When we emit postponed boundaries, we might have assigned the ID already
+ // but it's still the root segment so we can't inject it into the parent yet.
+ return flushSegmentContainer(request, destination, segment);
+ } else {
+ flushSegmentContainer(request, destination, segment);
+ return writeCompletedSegmentInstruction(destination, request.resumableState, request.renderState, segmentID);
+ }
+}
+
+function flushCompletedQueues(request, destination) {
+
+ try {
+ // The structure of this is to go through each queue one by one and write
+ // until the sink tells us to stop. When we should stop, we still finish writing
+ // that item fully and then yield. At that point we remove the already completed
+ // items up until the point we completed them.
+ let i;
+ const completedRootSegment = request.completedRootSegment;
+
+ if (completedRootSegment !== null) {
+ if (completedRootSegment.status === POSTPONED) {
+ // We postponed the root, so we write nothing.
+ return;
+ } else if (request.pendingRootTasks === 0) {
+ if (enableFloat) {
+ writePreamble(destination, request.resumableState, request.renderState, request.allPendingTasks === 0 && request.trackedPostpones === null);
+ }
+
+ flushSegment(request, destination, completedRootSegment);
+ request.completedRootSegment = null;
+ writeCompletedRoot(destination, request.renderState, request.resumableState);
+ } else {
+ // We haven't flushed the root yet so we don't need to check any other branches further down
+ return;
+ }
+ }
+
+ if (enableFloat) {
+ writeHoistables(destination, request.resumableState, request.renderState);
+ } // We emit client rendering instructions for already emitted boundaries first.
+ // This is so that we can signal to the client to start client rendering them as
+ // soon as possible.
+
+
+ const clientRenderedBoundaries = request.clientRenderedBoundaries;
+
+ for (i = 0; i < clientRenderedBoundaries.length; i++) {
+ const boundary = clientRenderedBoundaries[i];
+
+ if (!flushClientRenderedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ clientRenderedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries
+ // that are completely done since we can actually show them, than it is to emit
+ // any individual segments from a partially complete boundary.
+
+ const completedBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < completedBoundaries.length; i++) {
+ const boundary = completedBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ completedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before
+ // we continue with lower priorities.
+
+ completeWriting(destination);
+ beginWriting(destination); // TODO: Here we'll emit data used by hydration.
+ // Next we emit any segments of any boundaries that are partially complete
+ // but not deeply complete.
+
+ const partialBoundaries = request.partialBoundaries;
+
+ for (i = 0; i < partialBoundaries.length; i++) {
+ const boundary = partialBoundaries[i];
+
+ if (!flushPartialBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ partialBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had
+ // boundaries added to it in case they were too larged to be inlined.
+ // New ones might be added in this loop.
+
+ const largeBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < largeBoundaries.length; i++) {
+ const boundary = largeBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ largeBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ largeBoundaries.splice(0, i);
+ } finally {
+ if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because
+ // either they have pending task or they're complete.
+ ) {
+ request.flushScheduled = false;
+
+ {
+ // We write the trailing tags but only if don't have any data to resume.
+ // If we need to resume we'll write the postamble in the resume instead.
+ {
+ writePostamble(destination, request.resumableState);
+ }
+ }
+
+
+ close(destination); // We need to stop flowing now because we do not want any async contexts which might call
+ // float methods to initiate any flushes after this point
+
+ stopFlowing(request);
+ }
+ }
+}
+
+function startWork(request) {
+ request.flushScheduled = request.destination !== null;
+
+ {
+ scheduleWork(() => performWork(request));
+ }
+
+ if (request.trackedPostpones === null) {
+ // this is either a regular render or a resume. For regular render we want
+ // to call emitEarlyPreloads after the first performWork because we want
+ // are responding to a live request and need to balance sending something early
+ // (i.e. don't want for the shell to finish) but we need something to send.
+ // The only implementation of this is for DOM at the moment and during resumes nothing
+ // actually emits but the code paths here are the same.
+ // During a prerender we don't want to be too aggressive in emitting early preloads
+ // because we aren't responding to a live request and we can wait for the prerender to
+ // postpone before we emit anything.
+ {
+ scheduleWork(() => enqueueEarlyPreloadsAfterInitialWork(request));
+ }
+ }
+}
+
+function enqueueEarlyPreloadsAfterInitialWork(request) {
+ const shellComplete = request.pendingRootTasks === 0;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+
+function enqueueFlush(request) {
+ if (request.flushScheduled === false && // If there are pinged tasks we are going to flush anyway after work completes
+ request.pingedTasks.length === 0 && // If there is no destination there is nothing we can flush to. A flush will
+ // happen when we start flowing again
+ request.destination !== null) {
+ request.flushScheduled = true;
+ scheduleWork(() => {
+ // We need to existence check destination again here because it might go away
+ // in between the enqueueFlush call and the work execution
+ const destination = request.destination;
+
+ if (destination) {
+ flushCompletedQueues(request, destination);
+ } else {
+ request.flushScheduled = false;
+ }
+ });
+ }
+} // This function is intented to only be called during the pipe function for the Node builds.
+function startFlowing(request, destination) {
+ if (request.status === CLOSING) {
+ request.status = CLOSED;
+ closeWithError(destination, request.fatalError);
+ return;
+ }
+
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ if (request.destination !== null) {
+ // We're already flowing.
+ return;
+ }
+
+ request.destination = destination;
+
+ try {
+ flushCompletedQueues(request, destination);
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function stopFlowing(request) {
+ request.destination = null;
+} // This is called to early terminate a request. It puts all pending boundaries in client rendered state.
+
+function abort(request, reason) {
+ try {
+ const abortableTasks = request.abortableTasks;
+
+ if (abortableTasks.size > 0) {
+ const error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason;
+ abortableTasks.forEach(task => abortTask(task, request, error));
+ abortableTasks.clear();
+ }
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function flushResources(request) {
+ enqueueFlush(request);
+}
+function getFormState(request) {
+ return request.formState;
+}
+function getResumableState(request) {
+ return request.resumableState;
+}
+function getRenderState(request) {
+ return request.renderState;
+}
+
+function onError$1() {// Non-fatal errors are ignored.
+}
+
+function renderToStringImpl(children, options, generateStaticMarkup, abortReason) {
+ let didFatal = false;
+ let fatalError = null;
+ let result = '';
+ const destination = {
+ // $FlowFixMe[missing-local-annot]
+ push(chunk) {
+ if (chunk !== null) {
+ result += chunk;
+ }
+
+ return true;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ destroy(error) {
+ didFatal = true;
+ fatalError = error;
+ }
+
+ };
+ let readyToStream = false;
+
+ function onShellReady() {
+ readyToStream = true;
+ }
+
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, undefined);
+ const request = createRequest(children, resumableState, createRenderState(resumableState, generateStaticMarkup), createRootFormatContext(), Infinity, onError$1, undefined, onShellReady, undefined, undefined, undefined);
+ startWork(request); // If anything suspended and is still pending, we'll abort it before writing.
+ // That way we write only client-rendered boundaries from the start.
+
+ abort(request, abortReason);
+ startFlowing(request, destination);
+
+ if (didFatal && fatalError !== abortReason) {
+ throw fatalError;
+ }
+
+ if (!readyToStream) {
+ // Note: This error message is the one we use on the client. It doesn't
+ // really make sense here. But this is the legacy server renderer, anyway.
+ // We're going to delete it soon.
+ throw new Error('A component suspended while responding to synchronous input. This ' + 'will cause the UI to be replaced with a loading indicator. To fix, ' + 'updates that suspend should be wrapped with startTransition.');
+ }
+
+ return result;
+}
+
+function _inheritsLoose(subClass, superClass) {
+ subClass.prototype = Object.create(superClass.prototype);
+ subClass.prototype.constructor = subClass;
+ subClass.__proto__ = superClass;
+}
+
+let ReactMarkupReadableStream = /*#__PURE__*/function (_Readable) {
+ _inheritsLoose(ReactMarkupReadableStream, _Readable);
+
+ function ReactMarkupReadableStream() {
+ var _this;
+
+ // Calls the stream.Readable(options) constructor. Consider exposing built-in
+ // features like highWaterMark in the future.
+ _this = _Readable.call(this, {}) || this;
+ _this.request = void 0;
+ _this.startedFlowing = void 0;
+ _this.request = null;
+ _this.startedFlowing = false;
+ return _this;
+ } // $FlowFixMe[missing-local-annot]
+
+
+ var _proto = ReactMarkupReadableStream.prototype;
+
+ _proto._destroy = function _destroy(err, callback) {
+ abort(this.request);
+ callback(err);
+ } // $FlowFixMe[missing-local-annot]
+ ;
+
+ _proto._read = function _read(size) {
+ if (this.startedFlowing) {
+ startFlowing(this.request, this);
+ }
+ };
+
+ return ReactMarkupReadableStream;
+}(stream.Readable);
+
+function onError() {// Non-fatal errors are ignored.
+}
+
+function renderToNodeStreamImpl(children, options, generateStaticMarkup) {
+ function onAllReady() {
+ // We wait until everything has loaded before starting to write.
+ // That way we only end up with fully resolved HTML even if we suspend.
+ destination.startedFlowing = true;
+ startFlowing(request, destination);
+ }
+
+ const destination = new ReactMarkupReadableStream();
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, undefined);
+ const request = createRequest(children, resumableState, createRenderState(resumableState, false), createRootFormatContext(), Infinity, onError, onAllReady, undefined, undefined, undefined);
+ destination.request = request;
+ startWork(request);
+ return destination;
+}
+
+function renderToNodeStream(children, options) {
+
+ return renderToNodeStreamImpl(children, options);
+}
+
+function renderToStaticNodeStream(children, options) {
+ return renderToNodeStreamImpl(children, options);
+}
+
+function renderToString(children, options) {
+ return renderToStringImpl(children, options, false, 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server');
+}
+
+function renderToStaticMarkup(children, options) {
+ return renderToStringImpl(children, options, true, 'The server used "renderToStaticMarkup" which does not support Suspense. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server');
+}
+
+exports.renderToNodeStream = renderToNodeStream;
+exports.renderToStaticMarkup = renderToStaticMarkup;
+exports.renderToStaticNodeStream = renderToStaticNodeStream;
+exports.renderToString = renderToString;
+exports.version = ReactVersion;
\ No newline at end of file
diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.production.min.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.production.min.js
index 58baa62e18901..5af836faae567 100644
--- a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.production.min.js
+++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.production.min.js
@@ -1,13 +1,11 @@
-/**
- * @license React
- * react-dom-server-legacy.node.production.min.js
- *
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
/*
+ React
+ react-dom-server-legacy.node.production.min.js
+
+ Copyright (c) Meta Platforms, Inc. and affiliates.
+
+ This source code is licensed under the MIT license found in the
+ LICENSE file in the root directory of this source tree.
JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
@@ -31,183 +29,188 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
-'use strict';var da=require("next/dist/compiled/react"),ja=require("react-dom"),ka=require("stream");
-function la(a,b){var c=a.length&3;var d=a.length-c;var e=b;for(b=0;b>>16)&65535)<<16)&4294967295;f=f<<15|f>>>17;f=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295;e^=f;e=e<<13|e>>>19;e=5*(e&65535)+((5*(e>>>16)&65535)<<16)&4294967295;e=(e&65535)+27492+(((e>>>16)+58964&65535)<<16)}f=0;switch(c){case 3:f^=(a.charCodeAt(b+2)&255)<<
+'use strict';var aa=require("next/dist/compiled/react"),da=require("react-dom"),ja=require("stream");
+function ka(a,b){var c=a.length&3;var d=a.length-c;var e=b;for(b=0;b>>16)&65535)<<16)&4294967295;f=f<<15|f>>>17;f=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295;e^=f;e=e<<13|e>>>19;e=5*(e&65535)+((5*(e>>>16)&65535)<<16)&4294967295;e=(e&65535)+27492+(((e>>>16)+58964&65535)<<16)}f=0;switch(c){case 3:f^=(a.charCodeAt(b+2)&255)<<
16;case 2:f^=(a.charCodeAt(b+1)&255)<<8;case 1:f^=a.charCodeAt(b)&255,f=3432918353*(f&65535)+((3432918353*(f>>>16)&65535)<<16)&4294967295,f=f<<15|f>>>17,e^=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295}e^=a.length;e^=e>>>16;e=2246822507*(e&65535)+((2246822507*(e>>>16)&65535)<<16)&4294967295;e^=e>>>13;e=3266489909*(e&65535)+((3266489909*(e>>>16)&65535)<<16)&4294967295;return(e^e>>>16)>>>0}
-var r=Object.assign,u=Object.prototype.hasOwnProperty,ya=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD][:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$"),za={},Aa={};
-function Ba(a){if(u.call(Aa,a))return!0;if(u.call(za,a))return!1;if(ya.test(a))return Aa[a]=!0;za[a]=!0;return!1}
-var Ca=new Set("animationIterationCount aspectRatio borderImageOutset borderImageSlice borderImageWidth boxFlex boxFlexGroup boxOrdinalGroup columnCount columns flex flexGrow flexPositive flexShrink flexNegative flexOrder gridArea gridRow gridRowEnd gridRowSpan gridRowStart gridColumn gridColumnEnd gridColumnSpan gridColumnStart fontWeight lineClamp lineHeight opacity order orphans scale tabSize widows zIndex zoom fillOpacity floodOpacity stopOpacity strokeDasharray strokeDashoffset strokeMiterlimit strokeOpacity strokeWidth MozAnimationIterationCount MozBoxFlex MozBoxFlexGroup MozLineClamp msAnimationIterationCount msFlex msZoom msFlexGrow msFlexNegative msFlexOrder msFlexPositive msFlexShrink msGridColumn msGridColumnSpan msGridRow msGridRowSpan WebkitAnimationIterationCount WebkitBoxFlex WebKitBoxFlexGroup WebkitBoxOrdinalGroup WebkitColumnCount WebkitColumns WebkitFlex WebkitFlexGrow WebkitFlexPositive WebkitFlexShrink WebkitLineClamp".split(" ")),Ia=
+var r=Object.assign,x=Object.prototype.hasOwnProperty,la=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD][:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$"),ya={},za={};
+function Aa(a){if(x.call(za,a))return!0;if(x.call(ya,a))return!1;if(la.test(a))return za[a]=!0;ya[a]=!0;return!1}
+var Ba=new Set("animationIterationCount aspectRatio borderImageOutset borderImageSlice borderImageWidth boxFlex boxFlexGroup boxOrdinalGroup columnCount columns flex flexGrow flexPositive flexShrink flexNegative flexOrder gridArea gridRow gridRowEnd gridRowSpan gridRowStart gridColumn gridColumnEnd gridColumnSpan gridColumnStart fontWeight lineClamp lineHeight opacity order orphans scale tabSize widows zIndex zoom fillOpacity floodOpacity stopOpacity strokeDasharray strokeDashoffset strokeMiterlimit strokeOpacity strokeWidth MozAnimationIterationCount MozBoxFlex MozBoxFlexGroup MozLineClamp msAnimationIterationCount msFlex msZoom msFlexGrow msFlexNegative msFlexOrder msFlexPositive msFlexShrink msGridColumn msGridColumnSpan msGridRow msGridRowSpan WebkitAnimationIterationCount WebkitBoxFlex WebKitBoxFlexGroup WebkitBoxOrdinalGroup WebkitColumnCount WebkitColumns WebkitFlex WebkitFlexGrow WebkitFlexPositive WebkitFlexShrink WebkitLineClamp".split(" ")),Ca=
new Map([["acceptCharset","accept-charset"],["htmlFor","for"],["httpEquiv","http-equiv"],["crossOrigin","crossorigin"],["accentHeight","accent-height"],["alignmentBaseline","alignment-baseline"],["arabicForm","arabic-form"],["baselineShift","baseline-shift"],["capHeight","cap-height"],["clipPath","clip-path"],["clipRule","clip-rule"],["colorInterpolation","color-interpolation"],["colorInterpolationFilters","color-interpolation-filters"],["colorProfile","color-profile"],["colorRendering","color-rendering"],
["dominantBaseline","dominant-baseline"],["enableBackground","enable-background"],["fillOpacity","fill-opacity"],["fillRule","fill-rule"],["floodColor","flood-color"],["floodOpacity","flood-opacity"],["fontFamily","font-family"],["fontSize","font-size"],["fontSizeAdjust","font-size-adjust"],["fontStretch","font-stretch"],["fontStyle","font-style"],["fontVariant","font-variant"],["fontWeight","font-weight"],["glyphName","glyph-name"],["glyphOrientationHorizontal","glyph-orientation-horizontal"],["glyphOrientationVertical",
"glyph-orientation-vertical"],["horizAdvX","horiz-adv-x"],["horizOriginX","horiz-origin-x"],["imageRendering","image-rendering"],["letterSpacing","letter-spacing"],["lightingColor","lighting-color"],["markerEnd","marker-end"],["markerMid","marker-mid"],["markerStart","marker-start"],["overlinePosition","overline-position"],["overlineThickness","overline-thickness"],["paintOrder","paint-order"],["panose-1","panose-1"],["pointerEvents","pointer-events"],["renderingIntent","rendering-intent"],["shapeRendering",
"shape-rendering"],["stopColor","stop-color"],["stopOpacity","stop-opacity"],["strikethroughPosition","strikethrough-position"],["strikethroughThickness","strikethrough-thickness"],["strokeDasharray","stroke-dasharray"],["strokeDashoffset","stroke-dashoffset"],["strokeLinecap","stroke-linecap"],["strokeLinejoin","stroke-linejoin"],["strokeMiterlimit","stroke-miterlimit"],["strokeOpacity","stroke-opacity"],["strokeWidth","stroke-width"],["textAnchor","text-anchor"],["textDecoration","text-decoration"],
["textRendering","text-rendering"],["transformOrigin","transform-origin"],["underlinePosition","underline-position"],["underlineThickness","underline-thickness"],["unicodeBidi","unicode-bidi"],["unicodeRange","unicode-range"],["unitsPerEm","units-per-em"],["vAlphabetic","v-alphabetic"],["vHanging","v-hanging"],["vIdeographic","v-ideographic"],["vMathematical","v-mathematical"],["vectorEffect","vector-effect"],["vertAdvY","vert-adv-y"],["vertOriginX","vert-origin-x"],["vertOriginY","vert-origin-y"],
-["wordSpacing","word-spacing"],["writingMode","writing-mode"],["xmlnsXlink","xmlns:xlink"],["xHeight","x-height"]]),Ja=/["'&<>]/;
-function v(a){if("boolean"===typeof a||"number"===typeof a)return""+a;a=""+a;var b=Ja.exec(a);if(b){var c="",d,e=0;for(d=b.index;d ")}
-function Fb(a,b,c,d,e,f,g,h){var k=null;"function"===typeof d&&("function"===typeof d.$$FORM_ACTION?(e=Cb(b),b=d.$$FORM_ACTION(e),h=b.name,d=b.action||"",e=b.encType,f=b.method,g=b.target,k=b.data):(a.push(" ","formAction",'="',Db,'"'),g=f=e=d=h=null,Gb(b,c)));null!=h&&E(a,"name",h);null!=d&&E(a,"formAction",d);null!=e&&E(a,"formEncType",e);null!=f&&E(a,"formMethod",f);null!=g&&E(a,"formTarget",g);return k}
-function E(a,b,c){switch(b){case "className":D(a,"class",c);break;case "tabIndex":D(a,"tabindex",c);break;case "dir":case "role":case "viewBox":case "width":case "height":D(a,b,c);break;case "style":Ab(a,c);break;case "src":case "href":case "action":case "formAction":if(null==c||"function"===typeof c||"symbol"===typeof c||"boolean"===typeof c)break;a.push(" ",b,'="',v(""+c),'"');break;case "defaultValue":case "defaultChecked":case "innerHTML":case "suppressContentEditableWarning":case "suppressHydrationWarning":break;
-case "autoFocus":case "multiple":case "muted":Bb(a,b.toLowerCase(),c);break;case "xlinkHref":if("function"===typeof c||"symbol"===typeof c||"boolean"===typeof c)break;a.push(" ","xlink:href",'="',v(""+c),'"');break;case "contentEditable":case "spellCheck":case "draggable":case "value":case "autoReverse":case "externalResourcesRequired":case "focusable":case "preserveAlpha":"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'="',v(c),'"');break;case "allowFullScreen":case "async":case "autoPlay":case "controls":case "default":case "defer":case "disabled":case "disablePictureInPicture":case "disableRemotePlayback":case "formNoValidate":case "hidden":case "loop":case "noModule":case "noValidate":case "open":case "playsInline":case "readOnly":case "required":case "reversed":case "scoped":case "seamless":case "itemScope":c&&
-"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'=""');break;case "capture":case "download":!0===c?a.push(" ",b,'=""'):!1!==c&&"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'="',v(c),'"');break;case "cols":case "rows":case "size":case "span":"function"!==typeof c&&"symbol"!==typeof c&&!isNaN(c)&&1<=c&&a.push(" ",b,'="',v(c),'"');break;case "rowSpan":case "start":"function"===typeof c||"symbol"===typeof c||isNaN(c)||a.push(" ",b,'="',v(c),'"');break;case "xlinkActuate":D(a,"xlink:actuate",
-c);break;case "xlinkArcrole":D(a,"xlink:arcrole",c);break;case "xlinkRole":D(a,"xlink:role",c);break;case "xlinkShow":D(a,"xlink:show",c);break;case "xlinkTitle":D(a,"xlink:title",c);break;case "xlinkType":D(a,"xlink:type",c);break;case "xmlBase":D(a,"xml:base",c);break;case "xmlLang":D(a,"xml:lang",c);break;case "xmlSpace":D(a,"xml:space",c);break;default:if(!(2"))}
-function Ib(a,b,c,d,e,f,g){var h=b.rel,k=b.href,l=b.precedence;if(3===f||g||null!=b.itemProp||"string"!==typeof h||"string"!==typeof k||""===k)return J(a,b),null;if("stylesheet"===b.rel){if("string"!==typeof l||null!=b.disabled||b.onLoad||b.onError)return J(a,b);f=d.styles.get(l);g=c.styleResources.hasOwnProperty(k)?c.styleResources[k]:void 0;null!==g?(c.styleResources[k]=null,f||(f={precedence:v(l),rules:[],hrefs:[],sheets:new Map},d.styles.set(l,f)),b={state:0,props:r({},b,{"data-precedence":b.precedence,
-precedence:null})},g&&(2===g.length&&Jb(b.props,g),(c=d.preloads.stylesheets.get(k))&&0 ");return null}
-function Kb(a,b,c){a.push(K(c));for(var d in b)if(u.call(b,d)){var e=b[d];if(null!=e)switch(d){case "children":case "dangerouslySetInnerHTML":throw Error(c+" is a self-closing tag and must neither have `children` nor use `dangerouslySetInnerHTML`.");default:E(a,d,e)}}a.push("/>");return null}
-function Lb(a,b){a.push(K("title"));var c=null,d=null,e;for(e in b)if(u.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:E(a,e,f)}}a.push(">");b=Array.isArray(c)?2>c.length?c[0]:null:c;"function"!==typeof b&&"symbol"!==typeof b&&null!==b&&void 0!==b&&a.push(v(""+b));I(a,d,c);a.push(Mb("title"));return null}
-function Nb(a,b){a.push(K("script"));var c=null,d=null,e;for(e in b)if(u.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:E(a,e,f)}}a.push(">");I(a,d,c);"string"===typeof c&&a.push(v(c));a.push(Mb("script"));return null}
-function Ob(a,b,c){a.push(K(c));var d=c=null,e;for(e in b)if(u.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:E(a,e,f)}}a.push(">");I(a,d,c);return"string"===typeof c?(a.push(v(c)),null):c}var Pb=/^[a-zA-Z][a-zA-Z:_\.\-\d]*$/,Qb=new Map;function K(a){var b=Qb.get(a);if(void 0===b){if(!Pb.test(a))throw Error("Invalid tag: "+a);b="<"+a;Qb.set(a,b)}return b}
-function Rb(a,b,c,d,e,f,g){switch(b){case "div":case "span":case "svg":case "path":case "a":case "g":case "p":case "li":break;case "select":a.push(K("select"));var h=null,k=null,l;for(l in c)if(u.call(c,l)){var n=c[l];if(null!=n)switch(l){case "children":h=n;break;case "dangerouslySetInnerHTML":k=n;break;case "defaultValue":case "value":break;default:E(a,l,n)}}a.push(">");I(a,k,h);return h;case "option":var q=f.selectedValue;a.push(K("option"));var m=null,F=null,z=null,S=null,t;for(t in c)if(u.call(c,
-t)){var y=c[t];if(null!=y)switch(t){case "children":m=y;break;case "selected":z=y;break;case "dangerouslySetInnerHTML":S=y;break;case "value":F=y;default:E(a,t,y)}}if(null!=q){var p=null!==F?""+F:Hb(m);if(Ma(q))for(var Z=0;Z");I(a,S,m);return m;case "textarea":a.push(K("textarea"));var G=null,aa=null,A=null,L;for(L in c)if(u.call(c,L)){var w=c[L];if(null!=w)switch(L){case "children":A=
-w;break;case "value":G=w;break;case "defaultValue":aa=w;break;case "dangerouslySetInnerHTML":throw Error("`dangerouslySetInnerHTML` does not make sense on ')}
-function ec(a,b,c,d){switch(c.insertionMode){case 0:case 1:case 2:return a.push('');case 3:return a.push('
');case 4:return a.push('');case 5:return a.push(']/;
+function y(a){if("boolean"===typeof a||"number"===typeof a)return""+a;a=""+a;var b=Ia.exec(a);if(b){var c="",d,e=0;for(d=b.index;d ")}
+function Gb(a,b,c,d,e,f,g,h){var k=null;"function"===typeof d&&("function"===typeof d.$$FORM_ACTION?(e=Db(b),b=d.$$FORM_ACTION(e),h=b.name,d=b.action||"",e=b.encType,f=b.method,g=b.target,k=b.data):(a.push(" ","formAction",'="',Eb,'"'),g=f=e=d=h=null,Hb(b,c)));null!=h&&I(a,"name",h);null!=d&&I(a,"formAction",d);null!=e&&I(a,"formEncType",e);null!=f&&I(a,"formMethod",f);null!=g&&I(a,"formTarget",g);return k}
+function I(a,b,c){switch(b){case "className":H(a,"class",c);break;case "tabIndex":H(a,"tabindex",c);break;case "dir":case "role":case "viewBox":case "width":case "height":H(a,b,c);break;case "style":Bb(a,c);break;case "src":case "href":case "action":case "formAction":if(null==c||"function"===typeof c||"symbol"===typeof c||"boolean"===typeof c)break;a.push(" ",b,'="',y(""+c),'"');break;case "defaultValue":case "defaultChecked":case "innerHTML":case "suppressContentEditableWarning":case "suppressHydrationWarning":break;
+case "autoFocus":case "multiple":case "muted":Cb(a,b.toLowerCase(),c);break;case "xlinkHref":if("function"===typeof c||"symbol"===typeof c||"boolean"===typeof c)break;a.push(" ","xlink:href",'="',y(""+c),'"');break;case "contentEditable":case "spellCheck":case "draggable":case "value":case "autoReverse":case "externalResourcesRequired":case "focusable":case "preserveAlpha":"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'="',y(c),'"');break;case "allowFullScreen":case "async":case "autoPlay":case "controls":case "default":case "defer":case "disabled":case "disablePictureInPicture":case "disableRemotePlayback":case "formNoValidate":case "hidden":case "loop":case "noModule":case "noValidate":case "open":case "playsInline":case "readOnly":case "required":case "reversed":case "scoped":case "seamless":case "itemScope":c&&
+"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'=""');break;case "capture":case "download":!0===c?a.push(" ",b,'=""'):!1!==c&&"function"!==typeof c&&"symbol"!==typeof c&&a.push(" ",b,'="',y(c),'"');break;case "cols":case "rows":case "size":case "span":"function"!==typeof c&&"symbol"!==typeof c&&!isNaN(c)&&1<=c&&a.push(" ",b,'="',y(c),'"');break;case "rowSpan":case "start":"function"===typeof c||"symbol"===typeof c||isNaN(c)||a.push(" ",b,'="',y(c),'"');break;case "xlinkActuate":H(a,"xlink:actuate",
+c);break;case "xlinkArcrole":H(a,"xlink:arcrole",c);break;case "xlinkRole":H(a,"xlink:role",c);break;case "xlinkShow":H(a,"xlink:show",c);break;case "xlinkTitle":H(a,"xlink:title",c);break;case "xlinkType":H(a,"xlink:type",c);break;case "xmlBase":H(a,"xml:base",c);break;case "xmlLang":H(a,"xml:lang",c);break;case "xmlSpace":H(a,"xml:space",c);break;default:if(!(2"))}
+function Jb(a,b,c,d,e,f,g){var h=b.rel,k=b.href,l=b.precedence;if(3===f||g||null!=b.itemProp||"string"!==typeof h||"string"!==typeof k||""===k)return L(a,b),null;if("stylesheet"===b.rel){if("string"!==typeof l||null!=b.disabled||b.onLoad||b.onError)return L(a,b);f=d.styles.get(l);g=c.styleResources.hasOwnProperty(k)?c.styleResources[k]:void 0;null!==g?(c.styleResources[k]=null,f||(f={precedence:y(l),rules:[],hrefs:[],sheets:new Map},d.styles.set(l,f)),b={state:0,props:r({},b,{"data-precedence":b.precedence,
+precedence:null})},g&&(2===g.length&&Kb(b.props,g),(c=d.preloads.stylesheets.get(k))&&0 ");return null}
+function Lb(a,b,c){a.push(M(c));for(var d in b)if(x.call(b,d)){var e=b[d];if(null!=e)switch(d){case "children":case "dangerouslySetInnerHTML":throw Error(c+" is a self-closing tag and must neither have `children` nor use `dangerouslySetInnerHTML`.");default:I(a,d,e)}}a.push("/>");return null}
+function Mb(a,b){a.push(M("title"));var c=null,d=null,e;for(e in b)if(x.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:I(a,e,f)}}a.push(">");b=Array.isArray(c)?2>c.length?c[0]:null:c;"function"!==typeof b&&"symbol"!==typeof b&&null!==b&&void 0!==b&&a.push(y(""+b));K(a,d,c);a.push(Nb("title"));return null}
+function Ob(a,b){a.push(M("script"));var c=null,d=null,e;for(e in b)if(x.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:I(a,e,f)}}a.push(">");K(a,d,c);"string"===typeof c&&a.push(y(c));a.push(Nb("script"));return null}
+function Pb(a,b,c){a.push(M(c));var d=c=null,e;for(e in b)if(x.call(b,e)){var f=b[e];if(null!=f)switch(e){case "children":c=f;break;case "dangerouslySetInnerHTML":d=f;break;default:I(a,e,f)}}a.push(">");K(a,d,c);return"string"===typeof c?(a.push(y(c)),null):c}var Qb=/^[a-zA-Z][a-zA-Z:_\.\-\d]*$/,Rb=new Map;function M(a){var b=Rb.get(a);if(void 0===b){if(!Qb.test(a))throw Error("Invalid tag: "+a);b="<"+a;Rb.set(a,b)}return b}
+function Sb(a,b,c,d,e,f,g){switch(b){case "div":case "span":case "svg":case "path":case "a":case "g":case "p":case "li":break;case "select":a.push(M("select"));var h=null,k=null,l;for(l in c)if(x.call(c,l)){var n=c[l];if(null!=n)switch(l){case "children":h=n;break;case "dangerouslySetInnerHTML":k=n;break;case "defaultValue":case "value":break;default:I(a,l,n)}}a.push(">");K(a,k,h);return h;case "option":var q=f.selectedValue;a.push(M("option"));var m=null,E=null,C=null,Q=null,u;for(u in c)if(x.call(c,
+u)){var t=c[u];if(null!=t)switch(u){case "children":m=t;break;case "selected":C=t;break;case "dangerouslySetInnerHTML":Q=t;break;case "value":E=t;default:I(a,u,t)}}if(null!=q){var p=null!==E?""+E:Ib(m);if(La(q))for(var F=0;F");K(a,Q,m);return m;case "textarea":a.push(M("textarea"));var w=null,v=null,B=null,N;for(N in c)if(x.call(c,N)){var z=c[N];if(null!=z)switch(N){case "children":B=
+z;break;case "value":w=z;break;case "defaultValue":v=z;break;case "dangerouslySetInnerHTML":throw Error("`dangerouslySetInnerHTML` does not make sense on .");default:I(a,N,z)}}null===w&&null!==v&&(w=v);a.push(">");if(null!=B){if(null!=w)throw Error("If you supply `defaultValue` on a , do not pass children.");if(La(B)){if(1 can only have at most one child.");w=""+B[0]}w=""+B}"string"===typeof w&&"\n"===w[0]&&a.push("\n");null!==w&&a.push(y(""+w));
+return null;case "input":a.push(M("input"));var ea=null,T=null,O=null,ma=null,fa=null,X=null,Pa=null,Qa=null,Ra=null,na;for(na in c)if(x.call(c,na)){var R=c[na];if(null!=R)switch(na){case "children":case "dangerouslySetInnerHTML":throw Error("input is a self-closing tag and must neither have `children` nor use `dangerouslySetInnerHTML`.");case "name":ea=R;break;case "formAction":T=R;break;case "formEncType":O=R;break;case "formMethod":ma=R;break;case "formTarget":fa=R;break;case "defaultChecked":Ra=
+R;break;case "defaultValue":Pa=R;break;case "checked":Qa=R;break;case "value":X=R;break;default:I(a,na,R)}}var qb=Gb(a,d,e,T,O,ma,fa,ea);null!==Qa?Cb(a,"checked",Qa):null!==Ra&&Cb(a,"checked",Ra);null!==X?I(a,"value",X):null!==Pa&&I(a,"value",Pa);a.push("/>");null!==qb&&qb.forEach(Fb,a);return null;case "button":a.push(M("button"));var oa=null,pa=null,ba=null,qa=null,ra=null,Sa=null,sa=null,Ta;for(Ta in c)if(x.call(c,Ta)){var ca=c[Ta];if(null!=ca)switch(Ta){case "children":oa=ca;break;case "dangerouslySetInnerHTML":pa=
+ca;break;case "name":ba=ca;break;case "formAction":qa=ca;break;case "formEncType":ra=ca;break;case "formMethod":Sa=ca;break;case "formTarget":sa=ca;break;default:I(a,Ta,ca)}}var Oc=Gb(a,d,e,qa,ra,Sa,sa,ba);a.push(">");null!==Oc&&Oc.forEach(Fb,a);K(a,pa,oa);if("string"===typeof oa){a.push(y(oa));var Pc=null}else Pc=oa;return Pc;case "form":a.push(M("form"));var Ua=null,Qc=null,ha=null,Va=null,Wa=null,Xa=null,Ya;for(Ya in c)if(x.call(c,Ya)){var ia=c[Ya];if(null!=ia)switch(Ya){case "children":Ua=ia;
+break;case "dangerouslySetInnerHTML":Qc=ia;break;case "action":ha=ia;break;case "encType":Va=ia;break;case "method":Wa=ia;break;case "target":Xa=ia;break;default:I(a,Ya,ia)}}var Wb=null,Xb=null;if("function"===typeof ha)if("function"===typeof ha.$$FORM_ACTION){var ze=Db(d),Da=ha.$$FORM_ACTION(ze);ha=Da.action||"";Va=Da.encType;Wa=Da.method;Xa=Da.target;Wb=Da.data;Xb=Da.name}else a.push(" ","action",'="',Eb,'"'),Xa=Wa=Va=ha=null,Hb(d,e);null!=ha&&I(a,"action",ha);null!=Va&&I(a,"encType",Va);null!=
+Wa&&I(a,"method",Wa);null!=Xa&&I(a,"target",Xa);a.push(">");null!==Xb&&(a.push(' "),null!==Wb&&Wb.forEach(Fb,a));K(a,Qc,Ua);if("string"===typeof Ua){a.push(y(Ua));var Rc=null}else Rc=Ua;return Rc;case "menuitem":a.push(M("menuitem"));for(var rb in c)if(x.call(c,rb)){var Sc=c[rb];if(null!=Sc)switch(rb){case "children":case "dangerouslySetInnerHTML":throw Error("menuitems cannot have `children` nor `dangerouslySetInnerHTML`.");default:I(a,rb,Sc)}}a.push(">");
+return null;case "title":if(3===f.insertionMode||f.tagScope&1||null!=c.itemProp)var Tc=Mb(a,c);else Mb(e.hoistableChunks,c),Tc=null;return Tc;case "link":return Jb(a,c,d,e,g,f.insertionMode,!!(f.tagScope&1));case "script":var Yb=c.async;if("string"!==typeof c.src||!c.src||!Yb||"function"===typeof Yb||"symbol"===typeof Yb||c.onLoad||c.onError||3===f.insertionMode||f.tagScope&1||null!=c.itemProp)var Uc=Ob(a,c);else{var sb=c.src;if("module"===c.type){var tb=d.moduleScriptResources;var Vc=e.preloads.moduleScripts}else tb=
+d.scriptResources,Vc=e.preloads.scripts;var ub=tb.hasOwnProperty(sb)?tb[sb]:void 0;if(null!==ub){tb[sb]=null;var Zb=c;if(ub){2===ub.length&&(Zb=r({},c),Kb(Zb,ub));var Wc=Vc.get(sb);Wc&&(Wc.length=0)}var Xc=[];e.scripts.add(Xc);Ob(Xc,Zb)}g&&a.push("\x3c!-- --\x3e");Uc=null}return Uc;case "style":var vb=c.precedence,ta=c.href;if(3===f.insertionMode||f.tagScope&1||null!=c.itemProp||"string"!==typeof vb||"string"!==typeof ta||""===ta){a.push(M("style"));var Ea=null,Yc=null,Za;for(Za in c)if(x.call(c,
+Za)){var wb=c[Za];if(null!=wb)switch(Za){case "children":Ea=wb;break;case "dangerouslySetInnerHTML":Yc=wb;break;default:I(a,Za,wb)}}a.push(">");var $a=Array.isArray(Ea)?2>Ea.length?Ea[0]:null:Ea;"function"!==typeof $a&&"symbol"!==typeof $a&&null!==$a&&void 0!==$a&&a.push(y(""+$a));K(a,Yc,Ea);a.push(Nb("style"));var Zc=null}else{var ua=e.styles.get(vb);if(null!==(d.styleResources.hasOwnProperty(ta)?d.styleResources[ta]:void 0)){d.styleResources[ta]=null;ua?ua.hrefs.push(y(ta)):(ua={precedence:y(vb),
+rules:[],hrefs:[y(ta)],sheets:new Map},e.styles.set(vb,ua));var $c=ua.rules,Fa=null,ad=null,xb;for(xb in c)if(x.call(c,xb)){var $b=c[xb];if(null!=$b)switch(xb){case "children":Fa=$b;break;case "dangerouslySetInnerHTML":ad=$b}}var ab=Array.isArray(Fa)?2>Fa.length?Fa[0]:null:Fa;"function"!==typeof ab&&"symbol"!==typeof ab&&null!==ab&&void 0!==ab&&$c.push(y(""+ab));K($c,ad,Fa)}ua&&e.boundaryResources&&e.boundaryResources.styles.add(ua);g&&a.push("\x3c!-- --\x3e");Zc=void 0}return Zc;case "meta":if(3===
+f.insertionMode||f.tagScope&1||null!=c.itemProp)var bd=Lb(a,c,"meta");else g&&a.push("\x3c!-- --\x3e"),bd="string"===typeof c.charSet?Lb(e.charsetChunks,c,"meta"):"viewport"===c.name?Lb(e.preconnectChunks,c,"meta"):Lb(e.hoistableChunks,c,"meta");return bd;case "listing":case "pre":a.push(M(b));var bb=null,cb=null,db;for(db in c)if(x.call(c,db)){var yb=c[db];if(null!=yb)switch(db){case "children":bb=yb;break;case "dangerouslySetInnerHTML":cb=yb;break;default:I(a,db,yb)}}a.push(">");if(null!=cb){if(null!=
+bb)throw Error("Can only set one of `children` or `props.dangerouslySetInnerHTML`.");if("object"!==typeof cb||!("__html"in cb))throw Error("`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. Please visit https://reactjs.org/link/dangerously-set-inner-html for more information.");var va=cb.__html;null!==va&&void 0!==va&&("string"===typeof va&&0e.highImagePreloads.size)ac.delete(Ga),e.highImagePreloads.add(wa)}else if(!d.imageResources.hasOwnProperty(Ga)){d.imageResources[Ga]=A;var bc=c.crossOrigin;var dd="string"===typeof bc?"use-credentials"===bc?bc:"":void 0;var Y=e.headers,cc;Y&&0Y.highImagePreloads.length)&&(cc=Tb(J,"image",{imageSrcSet:c.srcSet,imageSizes:c.sizes,crossOrigin:dd,integrity:c.integrity,nonce:c.nonce,type:c.type,fetchPriority:c.fetchPriority,
+referrerPolicy:c.refererPolicy}),2<=(Y.remainingCapacity-=cc.length))?(e.resets.image[Ga]=A,Y.highImagePreloads&&(Y.highImagePreloads+=", "),Y.highImagePreloads+=cc):(wa=[],L(wa,{rel:"preload",as:"image",href:G?void 0:J,imageSrcSet:G,imageSizes:cd,crossOrigin:dd,integrity:c.integrity,type:c.type,fetchPriority:c.fetchPriority,referrerPolicy:c.referrerPolicy}),"high"===c.fetchPriority||10>e.highImagePreloads.size?e.highImagePreloads.add(wa):(e.bulkPreloads.add(wa),ac.set(Ga,wa)))}}return Lb(a,c,"img");
+case "base":case "area":case "br":case "col":case "embed":case "hr":case "keygen":case "param":case "source":case "track":case "wbr":return Lb(a,c,b);case "annotation-xml":case "color-profile":case "font-face":case "font-face-src":case "font-face-uri":case "font-face-format":case "font-face-name":case "missing-glyph":break;case "head":if(2>f.insertionMode&&null===e.headChunks){e.headChunks=[];var ed=Pb(e.headChunks,c,"head")}else ed=Pb(a,c,"head");return ed;case "html":if(0===f.insertionMode&&null===
+e.htmlChunks){e.htmlChunks=[""];var fd=Pb(e.htmlChunks,c,"html")}else fd=Pb(a,c,"html");return fd;default:if(-1!==b.indexOf("-")){a.push(M(b));var dc=null,gd=null,Ha;for(Ha in c)if(x.call(c,Ha)){var xa=c[Ha];if(null!=xa){var Ae=Ha;switch(Ha){case "children":dc=xa;break;case "dangerouslySetInnerHTML":gd=xa;break;case "style":Bb(a,xa);break;case "suppressContentEditableWarning":case "suppressHydrationWarning":break;default:Aa(Ha)&&"function"!==typeof xa&&"symbol"!==typeof xa&&a.push(" ",Ae,'="',y(xa),
+'"')}}}a.push(">");K(a,gd,dc);return dc}}return Pb(a,c,b)}var Ub=new Map;function Nb(a){var b=Ub.get(a);void 0===b&&(b=""+a+">",Ub.set(a,b));return b}function Vb(a,b,c){c.bootstrapScriptContent=void 0;c.bootstrapScripts=void 0;c.bootstrapModules=void 0;b=b.bootstrapChunks;for(c=0;c')}
+function fc(a,b,c,d){switch(c.insertionMode){case 0:case 1:case 2:return a.push('');case 3:return a.push('
');case 4:return a.push('');case 5:return a.push('');case 6:return a.push('');case 7:return a.push('');case 8:return a.push('');default:throw Error("Unknown insertion mode. This is a bug in React.");}}
-function fc(a,b){switch(b.insertionMode){case 0:case 1:case 2:return a.push("");case 3:return a.push("");case 4:return a.push("");case 5:return a.push("
");case 6:return a.push("
");case 7:return a.push("
");case 8:return a.push("
");default:throw Error("Unknown insertion mode. This is a bug in React.");}}var gc=/[<\u2028\u2029]/g;
-function hc(a){return JSON.stringify(a).replace(gc,function(b){switch(b){case "<":return"\\u003c";case "\u2028":return"\\u2028";case "\u2029":return"\\u2029";default:throw Error("escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}})}var ic=/[&><\u2028\u2029]/g;
-function jc(a){return JSON.stringify(a).replace(ic,function(b){switch(b){case "&":return"\\u0026";case ">":return"\\u003e";case "<":return"\\u003c";case "\u2028":return"\\u2028";case "\u2029":return"\\u2029";default:throw Error("escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}})}var kc=!1,lc=!0;
-function mc(a){var b=a.rules,c=a.hrefs,d=0;if(c.length){this.push('");kc=!0;b.length=0;c.length=0}}function nc(a){return 2!==a.state?kc=!0:!1}function oc(a,b,c){kc=!1;lc=!0;b.styles.forEach(mc,a);b.stylesheets.forEach(nc);kc&&(c.stylesToHoist=!0);return lc}
-function N(a){for(var b=0;b');for(a=0;a");c.length=0;d.length=0}}
-function sc(a){if(0===a.state){a.state=1;var b=a.props;J(pc,{rel:"preload",as:"style",href:a.props.href,crossOrigin:b.crossOrigin,fetchPriority:b.fetchPriority,integrity:b.integrity,media:b.media,hrefLang:b.hrefLang,referrerPolicy:b.referrerPolicy});for(a=0;a; rel=dns-prefetch",2<=(c.remainingCapacity-=e.length));f?(d.resets.dns[a]=null,c.preconnects&&(c.preconnects+=", "),c.preconnects+=e):(e=[],J(e,{href:a,rel:"dns-prefetch"}),d.preconnects.add(e))}yc(b)}}}
-function gb(a,b){var c=P?P:null;if(c){var d=c.resumableState,e=c.renderState;if("string"===typeof a&&a){var f="use-credentials"===b?"credentials":"string"===typeof b?"anonymous":"default";if(!d.connectResources[f].hasOwnProperty(a)){d.connectResources[f][a]=null;d=e.headers;var g,h;if(h=d&&0; rel=preconnect";if("string"===typeof b){var k=(""+b).replace(zc,Ac);h+='; crossorigin="'+k+'"'}h=(g=h,2<=(d.remainingCapacity-=g.length))}h?(e.resets.connect[f][a]=
-null,d.preconnects&&(d.preconnects+=", "),d.preconnects+=g):(f=[],J(f,{rel:"preconnect",href:a,crossOrigin:b}),e.preconnects.add(f))}yc(c)}}}
-function hb(a,b,c){var d=P?P:null;if(d){var e=d.resumableState,f=d.renderState;if(b&&a){switch(b){case "image":if(c){var g=c.imageSrcSet;var h=c.imageSizes;var k=c.fetchPriority}var l=g?g+"\n"+(h||""):a;if(e.imageResources.hasOwnProperty(l))return;e.imageResources[l]=x;e=f.headers;var n;e&&0; rel=preload; as="'+b+'"';for(var d in c)u.call(c,d)&&(a=c[d],"string"===typeof a&&(b+="; "+d.toLowerCase()+'="'+(""+a).replace(zc,Ac)+'"'));return b}var wc=/[<>\r\n]/g;
-function xc(a){switch(a){case "<":return"%3C";case ">":return"%3E";case "\n":return"%0A";case "\r":return"%0D";default:throw Error("escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}}var zc=/["';,\r\n]/g;
-function Ac(a){switch(a){case '"':return"%22";case "'":return"%27";case ";":return"%3B";case ",":return"%2C";case "\n":return"%0A";case "\r":return"%0D";default:throw Error("escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}}function Bc(a){this.styles.add(a)}function Cc(a){this.stylesheets.add(a)}
-function Dc(a,b,c){if(b=a.onHeaders){var d=a.headers;if(d){var e=d.preconnects;d.fontPreloads&&(e&&(e+=", "),e+=d.fontPreloads);d.highImagePreloads&&(e&&(e+=", "),e+=d.highImagePreloads);if(!c){c=a.styles.values();var f=c.next();a:for(;0",htmlChunks:null,headChunks:null,externalRuntimeScript:null,bootstrapChunks:[],onHeaders:void 0,headers:null,resets:{font:{},dns:{},connect:{default:{},anonymous:{},credentials:{}},image:{},style:{}},
-charsetChunks:[],preconnectChunks:[],importMapChunks:[],preloadChunks:[],hoistableChunks:[],preconnects:e,fontPreloads:f,highImagePreloads:g,styles:h,bootstrapScripts:k,scripts:l,bulkPreloads:n,preloads:q,boundaryResources:null,stylesToHoist:!1,generateStaticMarkup:b}}function Fc(a,b,c,d){if(c.generateStaticMarkup)return a.push(v(b)),!1;""===b?a=d:(d&&a.push("\x3c!-- --\x3e"),a.push(v(b)),a=!0);return a}
-var Gc=Symbol.for("react.element"),Hc=Symbol.for("react.portal"),Ic=Symbol.for("react.fragment"),Jc=Symbol.for("react.strict_mode"),Kc=Symbol.for("react.profiler"),Lc=Symbol.for("react.provider"),Mc=Symbol.for("react.context"),Nc=Symbol.for("react.server_context"),hd=Symbol.for("react.forward_ref"),id=Symbol.for("react.suspense"),jd=Symbol.for("react.suspense_list"),kd=Symbol.for("react.memo"),ld=Symbol.for("react.lazy"),md=Symbol.for("react.scope"),nd=Symbol.for("react.debug_trace_mode"),od=Symbol.for("react.offscreen"),
-pd=Symbol.for("react.legacy_hidden"),qd=Symbol.for("react.cache"),rd=Symbol.for("react.default_value"),sd=Symbol.iterator;
-function td(a){if(null==a)return null;if("function"===typeof a)return a.displayName||a.name||null;if("string"===typeof a)return a;switch(a){case Ic:return"Fragment";case Hc:return"Portal";case Kc:return"Profiler";case Jc:return"StrictMode";case id:return"Suspense";case jd:return"SuspenseList";case qd:return"Cache"}if("object"===typeof a)switch(a.$$typeof){case Mc:return(a.displayName||"Context")+".Consumer";case Lc:return(a._context.displayName||"Context")+".Provider";case hd:var b=a.render;a=a.displayName;
-a||(a=b.displayName||b.name||"",a=""!==a?"ForwardRef("+a+")":"ForwardRef");return a;case kd:return b=a.displayName||null,null!==b?b:td(a.type)||"Memo";case ld:b=a._payload;a=a._init;try{return td(a(b))}catch(c){}}return null}var ud={};function vd(a,b){a=a.contextTypes;if(!a)return ud;var c={},d;for(d in a)c[d]=b[d];return c}var wd=null;
-function xd(a,b){if(a!==b){a.context._currentValue2=a.parentValue;a=a.parent;var c=b.parent;if(null===a){if(null!==c)throw Error("The stacks must reach the root at the same time. This is a bug in React.");}else{if(null===c)throw Error("The stacks must reach the root at the same time. This is a bug in React.");xd(a,c)}b.context._currentValue2=b.value}}function yd(a){a.context._currentValue2=a.parentValue;a=a.parent;null!==a&&yd(a)}
-function zd(a){var b=a.parent;null!==b&&zd(b);a.context._currentValue2=a.value}function Ad(a,b){a.context._currentValue2=a.parentValue;a=a.parent;if(null===a)throw Error("The depth must equal at least at zero before reaching the root. This is a bug in React.");a.depth===b.depth?xd(a,b):Ad(a,b)}
-function Bd(a,b){var c=b.parent;if(null===c)throw Error("The depth must equal at least at zero before reaching the root. This is a bug in React.");a.depth===c.depth?xd(a,c):Bd(a,c);b.context._currentValue2=b.value}function Cd(a){var b=wd;b!==a&&(null===b?zd(a):null===a?yd(b):b.depth===a.depth?xd(b,a):b.depth>a.depth?Ad(b,a):Bd(b,a),wd=a)}
-var Dd={isMounted:function(){return!1},enqueueSetState:function(a,b){a=a._reactInternals;null!==a.queue&&a.queue.push(b)},enqueueReplaceState:function(a,b){a=a._reactInternals;a.replace=!0;a.queue=[b]},enqueueForceUpdate:function(){}};
-function Ed(a,b,c,d){var e=void 0!==a.state?a.state:null;a.updater=Dd;a.props=c;a.state=e;var f={queue:[],replace:!1};a._reactInternals=f;var g=b.contextType;a.context="object"===typeof g&&null!==g?g._currentValue2:d;g=b.getDerivedStateFromProps;"function"===typeof g&&(g=g(c,e),e=null===g||void 0===g?e:r({},e,g),a.state=e);if("function"!==typeof b.getDerivedStateFromProps&&"function"!==typeof a.getSnapshotBeforeUpdate&&("function"===typeof a.UNSAFE_componentWillMount||"function"===typeof a.componentWillMount))if(b=
-a.state,"function"===typeof a.componentWillMount&&a.componentWillMount(),"function"===typeof a.UNSAFE_componentWillMount&&a.UNSAFE_componentWillMount(),b!==a.state&&Dd.enqueueReplaceState(a,a.state,null),null!==f.queue&&0>=g;e-=g;return{id:1<<32-Hd(b)+e|c<>>=0;return 0===a?32:31-(Jd(a)/Kd|0)|0}var Ld=Error("Suspense Exception: This is not a real error! It's an implementation detail of `use` to interrupt the current render. You must either rethrow it immediately, or move the `use` call outside of the `try/catch` block. Capturing without rethrowing will lead to unexpected behavior.\n\nTo handle async errors, wrap your component in an error boundary, or call the promise's `.catch` method and pass the result to `use`");
-function Md(){}function Nd(a,b,c){c=a[c];void 0===c?a.push(b):c!==b&&(b.then(Md,Md),b=c);switch(b.status){case "fulfilled":return b.value;case "rejected":throw b.reason;default:if("string"!==typeof b.status)switch(a=b,a.status="pending",a.then(function(d){if("pending"===b.status){var e=b;e.status="fulfilled";e.value=d}},function(d){if("pending"===b.status){var e=b;e.status="rejected";e.reason=d}}),b.status){case "fulfilled":return b.value;case "rejected":throw b.reason;}Od=b;throw Ld;}}var Od=null;
-function Pd(){if(null===Od)throw Error("Expected a suspended thenable. This is a bug in React. Please file an issue.");var a=Od;Od=null;return a}function Qd(a,b){return a===b&&(0!==a||1/a===1/b)||a!==a&&b!==b}var Rd="function"===typeof Object.is?Object.is:Qd,R=null,Sd=null,Td=null,Ud=null,Vd=null,T=null,Wd=!1,Xd=!1,Yd=0,Zd=0,$d=-1,ae=0,be=null,ce=null,de=0;
-function ee(){if(null===R)throw Error("Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.");return R}
-function fe(){if(0=h.insertionMode){a.hasBody=!0;break a}break;case "html":if(0===h.insertionMode){a.hasHtml=!0;break a}}b.push(Mb(e))}d.lastPushedText=!1}else{switch(e){case pd:case nd:case Jc:case Kc:case Ic:e=b.keyPath;b.keyPath=c;X(a,b,null,f.children,-1);b.keyPath=e;return;case od:"hidden"!==f.mode&&(e=b.keyPath,b.keyPath=c,X(a,b,null,f.children,-1),b.keyPath=e);return;case jd:e=b.keyPath;b.keyPath=c;X(a,b,null,f.children,-1);b.keyPath=e;return;case md:throw Error("ReactDOMServer does not yet support scope components.");
-case id:a:if(null!==b.replay){e=b.keyPath;b.keyPath=c;c=f.children;try{Y(a,b,c,-1)}finally{b.keyPath=e}}else{l=b.keyPath;e=b.blockedBoundary;var n=b.blockedSegment;d=f.fallback;var q=f.children;f=new Set;g=He(a,f);null!==a.trackedPostpones&&(g.trackedContentKeyPath=c);k=De(a,n.chunks.length,g,b.formatContext,!1,!1);n.children.push(k);n.lastPushedText=!1;var m=De(a,0,null,b.formatContext,!1,!1);m.parentFlushed=!0;b.blockedBoundary=g;b.blockedSegment=m;a.renderState.boundaryResources=g.resources;b.keyPath=
-c;try{if(Y(a,b,q,-1),a.renderState.generateStaticMarkup||m.lastPushedText&&m.textEmbedded&&m.chunks.push("\x3c!-- --\x3e"),m.status=1,Oe(g,m),0===g.pendingTasks&&0===g.status){g.status=1;break a}}catch(F){m.status=4,g.status=4,h=U(a,F),g.errorDigest=h}finally{a.renderState.boundaryResources=e?e.resources:null,b.blockedBoundary=e,b.blockedSegment=n,b.keyPath=l}h=[c[0],"Suspense Fallback",c[2]];l=a.trackedPostpones;null!==l&&(n=[h[1],h[2],[],null],l.workingMap.set(h,n),5===g.status?l.workingMap.get(c)[4]=
-n:g.trackedFallbackNode=n);b=Ee(a,null,d,-1,e,k,f,h,b.formatContext,b.legacyContext,b.context,b.treeContext);a.pingedTasks.push(b)}return}if("object"===typeof e&&null!==e)switch(e.$$typeof){case hd:e=e.render;R={};Sd=b;Td=a;Ud=c;Zd=Yd=0;$d=-1;ae=0;be=d;d=e(f,g);f=he(e,f,d,g);Le(a,b,c,f,0!==Yd,Zd,$d);return;case kd:e=e.type;f=Me(e,f);Ne(a,b,c,d,e,f,g);return;case Lc:h=f.children;d=b.keyPath;e=e._context;f=f.value;g=e._currentValue2;e._currentValue2=f;k=wd;wd=f={parent:k,depth:null===k?0:k.depth+1,
-context:e,parentValue:g,value:f};b.context=f;b.keyPath=c;X(a,b,null,h,-1);a=wd;if(null===a)throw Error("Tried to pop a Context at the root of the app. This is a bug in React.");c=a.parentValue;a.context._currentValue2=c===rd?a.context._defaultValue:c;a=wd=a.parent;b.context=a;b.keyPath=d;return;case Mc:f=f.children;f=f(e._currentValue2);e=b.keyPath;b.keyPath=c;X(a,b,null,f,-1);b.keyPath=e;return;case ld:h=e._init;e=h(e._payload);f=Me(e,f);Ne(a,b,c,d,e,f,void 0);return}throw Error("Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: "+
-((null==e?e:typeof e)+"."));}}function Pe(a,b,c,d,e){var f=b.replay,g=b.blockedBoundary,h=De(a,0,null,b.formatContext,!1,!1);h.id=c;h.parentFlushed=!0;try{b.replay=null,b.blockedSegment=h,Y(a,b,d,e),h.status=1,null===g?a.completedRootSegment=h:(Oe(g,h),g.parentFlushed&&a.partialBoundaries.push(g))}finally{b.replay=f,b.blockedSegment=null}}
-function X(a,b,c,d,e){if(null!==b.replay&&"number"===typeof b.replay.slots)Pe(a,b,b.replay.slots,d,e);else{b.node=d;b.childIndex=e;if("object"===typeof d&&null!==d){switch(d.$$typeof){case Gc:var f=d.type,g=d.key,h=d.props,k=d.ref,l=td(f),n=null==g?-1===e?0:e:g;g=[b.keyPath,l,n];if(null!==b.replay)a:{var q=b.replay;e=q.nodes;for(d=0;d in this slot but instead it rendered <"+
-l+">. The tree doesn't match so React will fallback to client rendering.");l=m[2];m=m[3];n=b.node;b.replay={nodes:l,slots:m,pendingTasks:1};try{Ne(a,b,g,c,f,h,k);if(1===b.replay.pendingTasks&&0 in this slot but instead it rendered <"+(td(f)||"Unknown")+">. The tree doesn't match so React will fallback to client rendering.");b:{q=void 0;c=m[5];f=m[2];k=m[3];l=null===m[4]?[]:m[4][2];m=null===m[4]?null:m[4][3];n=b.keyPath;var F=b.replay,z=b.blockedBoundary,S=h.children;h=h.fallback;var t=new Set,y=He(a,t);y.parentFlushed=!0;y.rootSegmentID=c;b.blockedBoundary=
-y;b.replay={nodes:f,slots:k,pendingTasks:1};a.renderState.boundaryResources=y.resources;try{Y(a,b,S,-1);if(1===b.replay.pendingTasks&&0");case 3:return a.push(" ");case 4:return a.push("");case 5:return a.push("
");case 6:return a.push("");case 7:return a.push("");case 8:return a.push("");default:throw Error("Unknown insertion mode. This is a bug in React.");}}var hc=/[<\u2028\u2029]/g;
+function ic(a){return JSON.stringify(a).replace(hc,function(b){switch(b){case "<":return"\\u003c";case "\u2028":return"\\u2028";case "\u2029":return"\\u2029";default:throw Error("escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}})}var jc=/[&><\u2028\u2029]/g;
+function kc(a){return JSON.stringify(a).replace(jc,function(b){switch(b){case "&":return"\\u0026";case ">":return"\\u003e";case "<":return"\\u003c";case "\u2028":return"\\u2028";case "\u2029":return"\\u2029";default:throw Error("escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}})}var lc=!1,mc=!0;
+function nc(a){var b=a.rules,c=a.hrefs,d=0;if(c.length){this.push('");lc=!0;b.length=0;c.length=0}}function oc(a){return 2!==a.state?lc=!0:!1}function pc(a,b,c){lc=!1;mc=!0;b.styles.forEach(nc,a);b.stylesheets.forEach(oc);lc&&(c.stylesToHoist=!0);return mc}
+function P(a){for(var b=0;b');for(a=0;a");c.length=0;d.length=0}}
+function tc(a){if(0===a.state){a.state=1;var b=a.props;L(qc,{rel:"preload",as:"style",href:a.props.href,crossOrigin:b.crossOrigin,fetchPriority:b.fetchPriority,integrity:b.integrity,media:b.media,hrefLang:b.hrefLang,referrerPolicy:b.referrerPolicy});for(a=0;a; rel=dns-prefetch",2<=(c.remainingCapacity-=e.length));f?(d.resets.dns[a]=null,c.preconnects&&(c.preconnects+=", "),c.preconnects+=e):(e=[],L(e,{href:a,rel:"dns-prefetch"}),d.preconnects.add(e))}zc(b)}}}
+function fb(a,b){var c=S?S:null;if(c){var d=c.resumableState,e=c.renderState;if("string"===typeof a&&a){var f="use-credentials"===b?"credentials":"string"===typeof b?"anonymous":"default";if(!d.connectResources[f].hasOwnProperty(a)){d.connectResources[f][a]=null;d=e.headers;var g,h;if(h=d&&0; rel=preconnect";if("string"===typeof b){var k=(""+b).replace(Ac,Bc);h+='; crossorigin="'+k+'"'}h=(g=h,2<=(d.remainingCapacity-=g.length))}h?(e.resets.connect[f][a]=
+null,d.preconnects&&(d.preconnects+=", "),d.preconnects+=g):(f=[],L(f,{rel:"preconnect",href:a,crossOrigin:b}),e.preconnects.add(f))}zc(c)}}}
+function gb(a,b,c){var d=S?S:null;if(d){var e=d.resumableState,f=d.renderState;if(b&&a){switch(b){case "image":if(c){var g=c.imageSrcSet;var h=c.imageSizes;var k=c.fetchPriority}var l=g?g+"\n"+(h||""):a;if(e.imageResources.hasOwnProperty(l))return;e.imageResources[l]=A;e=f.headers;var n;e&&0; rel=preload; as="'+b+'"';for(var d in c)x.call(c,d)&&(a=c[d],"string"===typeof a&&(b+="; "+d.toLowerCase()+'="'+(""+a).replace(Ac,Bc)+'"'));return b}var xc=/[<>\r\n]/g;
+function yc(a){switch(a){case "<":return"%3C";case ">":return"%3E";case "\n":return"%0A";case "\r":return"%0D";default:throw Error("escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}}var Ac=/["';,\r\n]/g;
+function Bc(a){switch(a){case '"':return"%22";case "'":return"%27";case ";":return"%3B";case ",":return"%2C";case "\n":return"%0A";case "\r":return"%0D";default:throw Error("escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React");}}function Cc(a){this.styles.add(a)}function Dc(a){this.stylesheets.add(a)}
+function Ec(a,b,c){if(b=a.onHeaders){var d=a.headers;if(d){var e=d.preconnects;d.fontPreloads&&(e&&(e+=", "),e+=d.fontPreloads);d.highImagePreloads&&(e&&(e+=", "),e+=d.highImagePreloads);if(!c){c=a.styles.values();var f=c.next();a:for(;0",(""+e).replace(mb,nb),"\x3c/script>");e=c+"P:";var h=c+"S:";c+="B:";var k=new Set,l=new Set,n=new Set,q=new Map,m=new Set,E=new Set,C=new Set,Q={images:new Map,stylesheets:new Map,scripts:new Map,moduleScripts:new Map};if(void 0!==f)for(var u=0;u\x3c/script>')}if(void 0!==g)for(f=0;f\x3c/script>');return{placeholderPrefix:e,segmentPrefix:h,boundaryPrefix:c,startInlineScript:"');
+const startScriptSrc = stringToPrecomputedChunk('');
+/**
+ * This escaping function is designed to work with bootstrapScriptContent and importMap only.
+ * because we know we are escaping the entire script. We can avoid for instance
+ * escaping html comment string sequences that are valid javascript as well because
+ * if there are no sebsequent '); // Since we store headers as strings we deal with their length in utf16 code units
+// rather than visual characters or the utf8 encoding that is used for most binary
+// serialization. Some common HTTP servers only allow for headers to be 4kB in length.
+// We choose a default length that is likely to be well under this already limited length however
+// pathological cases may still cause the utf-8 encoding of the headers to approach this limit.
+// It should also be noted that this maximum is a soft maximum. we have not reached the limit we will
+// allow one more header to be captured which means in practice if the limit is approached it will be exceeded
+
+const DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep track of what we've already written so we can refer back to it.
+// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
+// is set, the server will send instructions via data attributes (instead of inline scripts)
+
+function createRenderState(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+ const inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const completeSegmentData1 = stringToPrecomputedChunk('');
+const completeBoundaryData1 = stringToPrecomputedChunk('');
+const clientRenderData1 = stringToPrecomputedChunk('
+ return writeChunkAndReturn(destination, clientRenderDataEnd);
+ }
+}
+const regexForJSStringsInInstructionScripts = /[<\u2028\u2029]/g;
+
+function escapeJSStringsForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInInstructionScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const regexForJSStringsInScripts = /[&><\u2028\u2029]/g;
+
+function escapeJSObjectForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '&':
+ return '\\u0026';
+
+ case '>':
+ return '\\u003e';
+
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(''); // Tracks whether the boundary currently flushing is flushign style tags or has any
+// stylesheet dependencies not flushed in the Preamble.
+
+let currentlyRenderingBoundaryHasStylesToHoist = false; // Acts as a return value for the forEach execution of style tag flushing.
+
+let destinationHasCapacity = true;
+
+function flushStyleTagsLateForBoundary(styleQueue) {
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs;
+
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, lateStyleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ writeChunk(this, lateStyleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, lateStyleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ destinationHasCapacity = writeChunkAndReturn(this, lateStyleTagTemplateClose); // We wrote style tags for this boundary and we may need to emit a script
+ // to hoist them.
+
+ currentlyRenderingBoundaryHasStylesToHoist = true; // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function hasStylesToHoist(stylesheet) {
+ // We need to reveal boundaries with styles whenever a stylesheet it depends on is either
+ // not flushed or flushed after the preamble (shell).
+ if (stylesheet.state !== PREAMBLE) {
+ currentlyRenderingBoundaryHasStylesToHoist = true;
+ return true;
+ }
+
+ return false;
+}
+
+function writeResourcesForBoundary(destination, boundaryResources, renderState) {
+ // Reset these on each invocation, they are only safe to read in this function
+ currentlyRenderingBoundaryHasStylesToHoist = false;
+ destinationHasCapacity = true; // Flush style tags for each precedence this boundary depends on
+
+ boundaryResources.styles.forEach(flushStyleTagsLateForBoundary, destination); // Determine if this boundary has stylesheets that need to be awaited upon completion
+
+ boundaryResources.stylesheets.forEach(hasStylesToHoist);
+
+ if (currentlyRenderingBoundaryHasStylesToHoist) {
+ renderState.stylesToHoist = true;
+ }
+
+ return destinationHasCapacity;
+}
+
+function flushResource(resource) {
+ for (let i = 0; i < resource.length; i++) {
+ writeChunk(this, resource[i]);
+ }
+
+ resource.length = 0;
+}
+
+const stylesheetFlushingQueue = [];
+
+function flushStyleInPreamble(stylesheet, key, map) {
+ // We still need to encode stylesheet chunks
+ // because unlike most Hoistables and Resources we do not eagerly encode
+ // them during render. This is because if we flush late we have to send a
+ // different encoding and we don't want to encode multiple times
+ pushLinkImpl(stylesheetFlushingQueue, stylesheet.props);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ stylesheet.state = PREAMBLE;
+}
+
+const styleTagResourceOpen1 = stringToPrecomputedChunk('');
+
+function flushStylesInPreamble(styleQueue, precedence) {
+ const hasStylesheets = styleQueue.sheets.size > 0;
+ styleQueue.sheets.forEach(flushStyleInPreamble, this);
+ styleQueue.sheets.clear();
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs; // If we don't emit any stylesheets at this precedence we still need to maintain the precedence
+ // order so even if there are no rules for style tags at this precedence we emit an empty style
+ // tag with the data-precedence attribute
+
+ if (!hasStylesheets || hrefs.length) {
+ writeChunk(this, styleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, styleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ }
+
+ writeChunk(this, styleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ writeChunk(this, styleTagResourceClose); // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function preloadLateStyle(stylesheet) {
+ if (stylesheet.state === PENDING$1) {
+ stylesheet.state = PRELOADED;
+ const preloadProps = preloadAsStylePropsFromProps(stylesheet.props.href, stylesheet.props);
+ pushLinkImpl(stylesheetFlushingQueue, preloadProps);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ }
+}
+
+function preloadLateStyles(styleQueue) {
+ styleQueue.sheets.forEach(preloadLateStyle, this);
+ styleQueue.sheets.clear();
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+
+function writePreamble(destination, resumableState, renderState, willFlushAllSegments) {
+ // This function must be called exactly once on every request
+ if (!willFlushAllSegments && renderState.externalRuntimeScript) {
+ // If the root segment is incomplete due to suspended tasks
+ // (e.g. willFlushAllSegments = false) and we are using data
+ // streaming format, ensure the external runtime is sent.
+ // (User code could choose to send this even earlier by calling
+ // preinit(...), if they know they will suspend).
+ const _renderState$external = renderState.externalRuntimeScript,
+ src = _renderState$external.src,
+ chunks = _renderState$external.chunks;
+ internalPreinitScript(resumableState, renderState, src, chunks);
+ }
+
+ const htmlChunks = renderState.htmlChunks;
+ const headChunks = renderState.headChunks;
+ let i = 0; // Emit open tags before Hoistables and Resources
+
+ if (htmlChunks) {
+ // We have an to emit as part of the preamble
+ for (i = 0; i < htmlChunks.length; i++) {
+ writeChunk(destination, htmlChunks[i]);
+ }
+
+ if (headChunks) {
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } else {
+ // We did not render a head but we emitted an so we emit one now
+ writeChunk(destination, startChunkForTag('head'));
+ writeChunk(destination, endOfStartTag);
+ }
+ } else if (headChunks) {
+ // We do not have an but we do have a
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } // Emit high priority Hoistables
+
+
+ const charsetChunks = renderState.charsetChunks;
+
+ for (i = 0; i < charsetChunks.length; i++) {
+ writeChunk(destination, charsetChunks[i]);
+ }
+
+ charsetChunks.length = 0; // emit preconnect resources
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Flush unblocked stylesheets by precedence
+
+ renderState.styles.forEach(flushStylesInPreamble, destination);
+ const importMapChunks = renderState.importMapChunks;
+
+ for (i = 0; i < importMapChunks.length; i++) {
+ writeChunk(destination, importMapChunks[i]);
+ }
+
+ importMapChunks.length = 0;
+ renderState.bootstrapScripts.forEach(flushResource, destination);
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0; // Flush closing head if necessary
+
+ if (htmlChunks && headChunks === null) {
+ // We have an rendered but no rendered. We however inserted
+ // a up above so we need to emit the now. This is safe because
+ // if the main content contained the it would also have provided a
+ // . This means that all the content inside is either or
+ // invalid HTML
+ writeChunk(destination, endChunkForTag('head'));
+ }
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+function writeHoistables(destination, resumableState, renderState) {
+ let i = 0; // Emit high priority Hoistables
+ // We omit charsetChunks because we have already sent the shell and if it wasn't
+ // already sent it is too late now.
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Preload any stylesheets. these will emit in a render instruction that follows this
+ // but we want to kick off preloading as soon as possible
+
+ renderState.styles.forEach(preloadLateStyles, destination); // We only hoist importmaps that are configured through createResponse and that will
+ // always flush in the preamble. Generally we don't expect people to render them as
+ // tags when using React but if you do they are going to be treated like regular inline
+ // scripts and flush after other hoistables which is problematic
+ // bootstrap scripts should flush above script priority but these can only flush in the preamble
+ // so we elide the code here for performance
+
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0;
+}
+function writePostamble(destination, resumableState) {
+ if (resumableState.hasBody) {
+ writeChunk(destination, endChunkForTag('body'));
+ }
+
+ if (resumableState.hasHtml) {
+ writeChunk(destination, endChunkForTag('html'));
+ }
+}
+const arrayFirstOpenBracket = stringToPrecomputedChunk('[');
+const arraySubsequentOpenBracket = stringToPrecomputedChunk(',[');
+const arrayInterstitial = stringToPrecomputedChunk(',');
+const arrayCloseBracket = stringToPrecomputedChunk(']'); // This function writes a 2D array of strings to be embedded in javascript.
+// E.g.
+// [["JS_escaped_string1", "JS_escaped_string2"]]
+
+function writeStyleResourceDependenciesInJS(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInJS(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInJS(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInJS(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+}
+
+function writeStyleResourceDependencyInJS(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedPrecedence)));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw Error(formatProdErrorMessage(399, 'link'));
+
+ default:
+ writeStyleResourceAttributeInJS(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInJS(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeName)));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeValue)));
+} // This function writes a 2D array of strings to be embedded in an attribute
+// value and read with JSON.parse in ReactDOMServerExternalRuntime.js
+// E.g.
+// [["JSON_escaped_string1", "JSON_escaped_string2"]]
+
+
+function writeStyleResourceDependenciesInAttr(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInAttr(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInAttr(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInAttr(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+}
+
+function writeStyleResourceDependencyInAttr(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedPrecedence))));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw Error(formatProdErrorMessage(399, 'link'));
+
+ default:
+ writeStyleResourceAttributeInAttr(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInAttr(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeName))));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeValue))));
+}
+/**
+ * Resources
+ */
+
+
+const PENDING$1 = 0;
+const PRELOADED = 1;
+const PREAMBLE = 2;
+const LATE = 3;
+function createBoundaryResources() {
+ return {
+ styles: new Set(),
+ stylesheets: new Set()
+ };
+}
+function setCurrentlyRenderingBoundaryResourcesTarget(renderState, boundaryResources) {
+ renderState.boundaryResources = boundaryResources;
+}
+
+function getResourceKey(href) {
+ return href;
+}
+
+function getImageResourceKey(href, imageSrcSet, imageSizes) {
+ if (imageSrcSet) {
+ return imageSrcSet + '\n' + (imageSizes || '');
+ }
+
+ return href;
+}
+
+function prefetchDNS(href) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const key = getResourceKey(href);
+
+ if (!resumableState.dnsResources.hasOwnProperty(key)) {
+ resumableState.dnsResources[key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPrefetchDNSAsHeader(href), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this as resettable in case we are prerendering and postpone in the Shell
+ renderState.resets.dns[key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ // Encode as element
+ const resource = [];
+ pushLinkImpl(resource, {
+ href,
+ rel: 'dns-prefetch'
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preconnect(href, crossOrigin) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const bucket = crossOrigin === 'use-credentials' ? 'credentials' : typeof crossOrigin === 'string' ? 'anonymous' : 'default';
+ const key = getResourceKey(href);
+
+ if (!resumableState.connectResources[bucket].hasOwnProperty(key)) {
+ resumableState.connectResources[bucket][key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreconnectAsHeader(href, crossOrigin), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this in resettableState in case we are prerending and postpone in the Shell
+ renderState.resets.connect[bucket][key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ const resource = [];
+ pushLinkImpl(resource, {
+ rel: 'preconnect',
+ href,
+ crossOrigin
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preload(href, as, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (as && href) {
+ switch (as) {
+ case 'image':
+ {
+ let imageSrcSet, imageSizes, fetchPriority;
+
+ if (options) {
+ imageSrcSet = options.imageSrcSet;
+ imageSizes = options.imageSizes;
+ fetchPriority = options.fetchPriority;
+ }
+
+ const key = getImageResourceKey(href, imageSrcSet, imageSizes);
+
+ if (resumableState.imageResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resumableState.imageResources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && fetchPriority === 'high' && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit a preload as a header so we
+ // track this to make sure we don't reset it.
+ renderState.resets.image[key] = PRELOAD_NO_CREDS;
+
+ if (headers.highImagePreloads) {
+ headers.highImagePreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.highImagePreloads += header;
+ } else {
+ // If we don't have headers to write to we have to encode as elements to flush in the head
+ // When we have imageSrcSet the browser probably cannot load the right version from headers
+ // (this should be verified by testing). For now we assume these need to go in the head
+ // as elements even if headers are available.
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ // There is a bug in Safari where imageSrcSet is not respected on preload links
+ // so we omit the href here if we have imageSrcSet b/c safari will load the wrong image.
+ // This harms older browers that do not support imageSrcSet by making their preloads not work
+ // but this population is shrinking fast and is already small so we accept this tradeoff.
+ href: imageSrcSet ? undefined : href,
+ as
+ }, options));
+
+ if (fetchPriority === 'high') {
+ renderState.highImagePreloads.add(resource);
+ } else {
+ renderState.bulkPreloads.add(resource); // Stash the resource in case we need to promote it to higher priority
+ // when an img tag is rendered
+
+ renderState.preloads.images.set(key, resource);
+ }
+ }
+
+ break;
+ }
+
+ case 'style':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.styleResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.styleResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.stylesheets.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ break;
+ }
+
+ case 'script':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.scriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ renderState.preloads.scripts.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.scriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ break;
+ }
+
+ default:
+ {
+ const key = getResourceKey(href);
+ const hasAsType = resumableState.unknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.unknownResources[as] = resources;
+ }
+
+ resources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && as === 'font' && ( // We compute the header here because we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit this preload so we
+ // track it here to prevent it from being reset.
+ renderState.resets.font[key] = PRELOAD_NO_CREDS;
+
+ if (headers.fontPreloads) {
+ headers.fontPreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.fontPreloads += header;
+ } else {
+ // We either don't have headers or we are preloading something that does
+ // not warrant elevated priority so we encode as an element.
+ const resource = [];
+
+ const props = assign({
+ rel: 'preload',
+ href,
+ as
+ }, options);
+
+ pushLinkImpl(resource, props);
+
+ switch (as) {
+ case 'font':
+ renderState.fontPreloads.add(resource);
+ break;
+ // intentional fall through
+
+ default:
+ renderState.bulkPreloads.add(resource);
+ }
+ }
+ }
+ } // If we got this far we created a new resource
+
+
+ flushResources(request);
+ }
+}
+
+function preloadModule(href, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ const key = getResourceKey(href);
+ const as = options && typeof options.as === 'string' ? options.as : 'script';
+ let resource;
+
+ switch (as) {
+ case 'script':
+ {
+ if (resumableState.moduleScriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resource = [];
+ resumableState.moduleScriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.moduleScripts.set(key, resource);
+ break;
+ }
+
+ default:
+ {
+ const hasAsType = resumableState.moduleUnknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.moduleUnknownResources[as] = resources;
+ }
+
+ resource = [];
+ resources[key] = PRELOAD_NO_CREDS;
+ }
+ }
+
+ pushLinkImpl(resource, assign({
+ rel: 'modulepreload',
+ href
+ }, options));
+ renderState.bulkPreloads.add(resource); // If we got this far we created a new resource
+
+ flushResources(request);
+ }
+}
+
+function preinitStyle(href, precedence, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ precedence = precedence || 'default';
+ const key = getResourceKey(href);
+ let styleQueue = renderState.styles.get(precedence);
+ const hasKey = resumableState.styleResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.styleResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.styleResources[key] = EXISTS; // If this is the first time we've encountered this precedence we need
+ // to create a StyleQueue
+
+ if (!styleQueue) {
+ styleQueue = {
+ precedence: stringToChunk(escapeTextForBrowser(precedence)),
+ rules: [],
+ hrefs: [],
+ sheets: new Map()
+ };
+ renderState.styles.set(precedence, styleQueue);
+ }
+
+ const resource = {
+ state: PENDING$1,
+ props: assign({
+ rel: 'stylesheet',
+ href,
+ 'data-precedence': precedence
+ }, options)
+ };
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(resource.props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.stylesheets.get(key);
+
+ if (preloadResource && preloadResource.length > 0) {
+ // The Preload for this resource was created in this render pass and has not flushed yet so
+ // we need to clear it to avoid it flushing.
+ preloadResource.length = 0;
+ } else {
+ // Either the preload resource from this render already flushed in this render pass
+ // or the preload flushed in a prior pass (prerender). In either case we need to mark
+ // this resource as already having been preloaded.
+ resource.state = PRELOADED;
+ }
+ } // We add the newly created resource to our StyleQueue and if necessary
+ // track the resource with the currently rendering boundary
+
+
+ styleQueue.sheets.set(key, resource); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+ }
+}
+
+function preinitScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.scriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.scriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.scriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.scripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+}
+
+function preinitModuleScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.moduleScriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.moduleScriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.moduleScriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ type: 'module',
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.moduleScripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+} // This function is only safe to call at Request start time since it assumes
+// that each module has not already been preloaded. If we find a need to preload
+// scripts at any other point in time we will need to check whether the preload
+// already exists and not assume it
+
+
+function preloadBootstrapScriptOrModule(resumableState, renderState, href, props) {
+
+ const key = getResourceKey(href);
+ // used to preinit the resource. If a script can be preinited then it shouldn't
+ // be a bootstrap script/module and if it is a bootstrap script/module then it
+ // must not be safe to emit early. To avoid possibly allowing for preinits of
+ // bootstrap scripts/modules we occlude these keys.
+
+
+ resumableState.scriptResources[key] = EXISTS;
+ resumableState.moduleScriptResources[key] = EXISTS;
+ const resource = [];
+ pushLinkImpl(resource, props);
+ renderState.bootstrapScripts.add(resource);
+}
+
+function internalPreinitScript(resumableState, renderState, src, chunks) {
+ const key = getResourceKey(src);
+
+ if (!resumableState.scriptResources.hasOwnProperty(key)) {
+ const resource = chunks;
+ resumableState.scriptResources[key] = EXISTS;
+ renderState.scripts.add(resource);
+ }
+
+ return;
+}
+
+function preloadAsStylePropsFromProps(href, props) {
+ return {
+ rel: 'preload',
+ as: 'style',
+ href: href,
+ crossOrigin: props.crossOrigin,
+ fetchPriority: props.fetchPriority,
+ integrity: props.integrity,
+ media: props.media,
+ hrefLang: props.hrefLang,
+ referrerPolicy: props.referrerPolicy
+ };
+}
+
+function stylesheetPropsFromRawProps(rawProps) {
+ return assign({}, rawProps, {
+ 'data-precedence': rawProps.precedence,
+ precedence: null
+ });
+}
+
+function adoptPreloadCredentials(target, preloadState) {
+ if (target.crossOrigin == null) target.crossOrigin = preloadState[0];
+ if (target.integrity == null) target.integrity = preloadState[1];
+}
+
+function getPrefetchDNSAsHeader(href) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ return "<" + escapedHref + ">; rel=dns-prefetch";
+}
+
+function getPreconnectAsHeader(href, crossOrigin) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ let value = "<" + escapedHref + ">; rel=preconnect";
+
+ if (typeof crossOrigin === 'string') {
+ const escapedCrossOrigin = escapeStringForLinkHeaderQuotedParamValueContext(crossOrigin);
+ value += "; crossorigin=\"" + escapedCrossOrigin + "\"";
+ }
+
+ return value;
+}
+
+function getPreloadAsHeader(href, as, params) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ const escapedAs = escapeStringForLinkHeaderQuotedParamValueContext(as);
+ let value = "<" + escapedHref + ">; rel=preload; as=\"" + escapedAs + "\"";
+
+ for (const paramName in params) {
+ if (hasOwnProperty.call(params, paramName)) {
+ const paramValue = params[paramName];
+
+ if (typeof paramValue === 'string') {
+ value += "; " + paramName.toLowerCase() + "=\"" + escapeStringForLinkHeaderQuotedParamValueContext(paramValue) + "\"";
+ }
+ }
+ }
+
+ return value;
+}
+
+function getStylesheetPreloadAsHeader(stylesheet) {
+ const props = stylesheet.props;
+ const preloadOptions = {
+ crossOrigin: props.crossOrigin,
+ integrity: props.integrity,
+ nonce: props.nonce,
+ type: props.type,
+ fetchPriority: props.fetchPriority,
+ referrerPolicy: props.referrerPolicy,
+ media: props.media
+ };
+ return getPreloadAsHeader(props.href, 'style', preloadOptions);
+} // This escaping function is only safe to use for href values being written into
+// a "Link" header in between `<` and `>` characters. The primary concern with the href is
+// to escape the bounding characters as well as new lines. This is unsafe to use in any other
+// context
+
+
+const regexForHrefInLinkHeaderURLContext = /[<>\r\n]/g;
+
+function escapeHrefForLinkHeaderURLContext(hrefInput) {
+
+ const coercedHref = '' + hrefInput;
+ return coercedHref.replace(regexForHrefInLinkHeaderURLContext, escapeHrefForLinkHeaderURLContextReplacer);
+}
+
+function escapeHrefForLinkHeaderURLContextReplacer(match) {
+ switch (match) {
+ case '<':
+ return '%3C';
+
+ case '>':
+ return '%3E';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+} // This escaping function is only safe to use for quoted param values in an HTTP header.
+// It is unsafe to use for any value not inside quote marks in parater value position.
+
+
+const regexForLinkHeaderQuotedParamValueContext = /["';,\r\n]/g;
+
+function escapeStringForLinkHeaderQuotedParamValueContext(value, name) {
+
+ const coerced = '' + value;
+ return coerced.replace(regexForLinkHeaderQuotedParamValueContext, escapeStringForLinkHeaderQuotedParamValueContextReplacer);
+}
+
+function escapeStringForLinkHeaderQuotedParamValueContextReplacer(match) {
+ switch (match) {
+ case '"':
+ return '%22';
+
+ case "'":
+ return '%27';
+
+ case ';':
+ return '%3B';
+
+ case ',':
+ return '%2C';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+}
+
+function hoistStyleQueueDependency(styleQueue) {
+ this.styles.add(styleQueue);
+}
+
+function hoistStylesheetDependency(stylesheet) {
+ this.stylesheets.add(stylesheet);
+}
+
+function hoistResources(renderState, source) {
+ const currentBoundaryResources = renderState.boundaryResources;
+
+ if (currentBoundaryResources) {
+ source.styles.forEach(hoistStyleQueueDependency, currentBoundaryResources);
+ source.stylesheets.forEach(hoistStylesheetDependency, currentBoundaryResources);
+ }
+} // This function is called at various times depending on whether we are rendering
+// or prerendering. In this implementation we only actually emit headers once and
+// subsequent calls are ignored. We track whether the request has a completed shell
+// to determine whether we will follow headers with a flush including stylesheets.
+// In the context of prerrender we don't have a completed shell when the request finishes
+// with a postpone in the shell. In the context of a render we don't have a completed shell
+// if this is called before the shell finishes rendering which usually will happen anytime
+// anything suspends in the shell.
+
+function emitEarlyPreloads(renderState, resumableState, shellComplete) {
+ const onHeaders = renderState.onHeaders;
+
+ if (onHeaders) {
+ const headers = renderState.headers;
+
+ if (headers) {
+ let linkHeader = headers.preconnects;
+
+ if (headers.fontPreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.fontPreloads;
+ }
+
+ if (headers.highImagePreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.highImagePreloads;
+ }
+
+ if (!shellComplete) {
+ // We use raw iterators because we want to be able to halt iteration
+ // We could refactor renderState to store these dually in arrays to
+ // make this more efficient at the cost of additional memory and
+ // write overhead. However this code only runs once per request so
+ // for now I consider this sufficient.
+ const queueIter = renderState.styles.values();
+
+ outer: for (let queueStep = queueIter.next(); headers.remainingCapacity > 0 && !queueStep.done; queueStep = queueIter.next()) {
+ const sheets = queueStep.value.sheets;
+ const sheetIter = sheets.values();
+
+ for (let sheetStep = sheetIter.next(); headers.remainingCapacity > 0 && !sheetStep.done; sheetStep = sheetIter.next()) {
+ const sheet = sheetStep.value;
+ const props = sheet.props;
+ const key = getResourceKey(props.href);
+ const header = getStylesheetPreloadAsHeader(sheet); // We mutate the capacity b/c we don't want to keep checking if later headers will fit.
+ // This means that a particularly long header might close out the header queue where later
+ // headers could still fit. We could in the future alter the behavior here based on prerender vs render
+ // since during prerender we aren't as concerned with pure runtime performance.
+
+ if ((headers.remainingCapacity -= header.length) >= 2) {
+ renderState.resets.style[key] = PRELOAD_NO_CREDS;
+
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += header; // We already track that the resource exists in resumableState however
+ // if the resumableState resets because we postponed in the shell
+ // which is what is happening in this branch if we are prerendering
+ // then we will end up resetting the resumableState. When it resets we
+ // want to record the fact that this stylesheet was already preloaded
+
+ renderState.resets.style[key] = typeof props.crossOrigin === 'string' || typeof props.integrity === 'string' ? [props.crossOrigin, props.integrity] : PRELOAD_NO_CREDS;
+ } else {
+ break outer;
+ }
+ }
+ }
+ }
+
+ if (linkHeader) {
+ onHeaders({
+ Link: linkHeader
+ });
+ } else {
+ // We still call this with no headers because a user may be using it as a signal that
+ // it React will not provide any headers
+ onHeaders({});
+ }
+
+ renderState.headers = null;
+ return;
+ }
+ }
+}
+const NotPendingTransition = NotPending;
+
+// ATTENTION
+// When adding new symbols to this file,
+// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
+// The Symbol used to tag the ReactElement-like types.
+const REACT_ELEMENT_TYPE = Symbol.for('react.element');
+const REACT_PORTAL_TYPE = Symbol.for('react.portal');
+const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
+const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
+const REACT_PROFILER_TYPE = Symbol.for('react.profiler');
+const REACT_PROVIDER_TYPE = Symbol.for('react.provider');
+const REACT_CONTEXT_TYPE = Symbol.for('react.context');
+const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
+const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
+const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
+const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
+const REACT_MEMO_TYPE = Symbol.for('react.memo');
+const REACT_LAZY_TYPE = Symbol.for('react.lazy');
+const REACT_SCOPE_TYPE = Symbol.for('react.scope');
+const REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');
+const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
+const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');
+const REACT_CACHE_TYPE = Symbol.for('react.cache');
+const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value');
+const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
+const FAUX_ITERATOR_SYMBOL = '@@iterator';
+function getIteratorFn(maybeIterable) {
+ if (maybeIterable === null || typeof maybeIterable !== 'object') {
+ return null;
+ }
+
+ const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
+
+ if (typeof maybeIterator === 'function') {
+ return maybeIterator;
+ }
+
+ return null;
+}
+
+function getWrappedName(outerType, innerType, wrapperName) {
+ const displayName = outerType.displayName;
+
+ if (displayName) {
+ return displayName;
+ }
+
+ const functionName = innerType.displayName || innerType.name || '';
+ return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName;
+} // Keep in sync with react-reconciler/getComponentNameFromFiber
+
+
+function getContextName(type) {
+ return type.displayName || 'Context';
+} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+
+
+function getComponentNameFromType(type) {
+ if (type == null) {
+ // Host root, text node or just invalid type.
+ return null;
+ }
+
+ if (typeof type === 'function') {
+ return type.displayName || type.name || null;
+ }
+
+ if (typeof type === 'string') {
+ return type;
+ }
+
+ switch (type) {
+ case REACT_FRAGMENT_TYPE:
+ return 'Fragment';
+
+ case REACT_PORTAL_TYPE:
+ return 'Portal';
+
+ case REACT_PROFILER_TYPE:
+ return 'Profiler';
+
+ case REACT_STRICT_MODE_TYPE:
+ return 'StrictMode';
+
+ case REACT_SUSPENSE_TYPE:
+ return 'Suspense';
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ return 'SuspenseList';
+
+ case REACT_CACHE_TYPE:
+ {
+ return 'Cache';
+ }
+
+ }
+
+ if (typeof type === 'object') {
+ switch (type.$$typeof) {
+ case REACT_CONTEXT_TYPE:
+ const context = type;
+ return getContextName(context) + '.Consumer';
+
+ case REACT_PROVIDER_TYPE:
+ const provider = type;
+ return getContextName(provider._context) + '.Provider';
+
+ case REACT_FORWARD_REF_TYPE:
+ return getWrappedName(type, type.render, 'ForwardRef');
+
+ case REACT_MEMO_TYPE:
+ const outerName = type.displayName || null;
+
+ if (outerName !== null) {
+ return outerName;
+ }
+
+ return getComponentNameFromType(type.type) || 'Memo';
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyComponent = type;
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+
+ try {
+ return getComponentNameFromType(init(payload));
+ } catch (x) {
+ return null;
+ }
+ }
+
+ }
+ }
+
+ return null;
+}
+
+const emptyContextObject = {};
+
+function getMaskedContext(type, unmaskedContext) {
+ {
+ const contextTypes = type.contextTypes;
+
+ if (!contextTypes) {
+ return emptyContextObject;
+ }
+
+ const context = {};
+
+ for (const key in contextTypes) {
+ context[key] = unmaskedContext[key];
+ }
+
+ return context;
+ }
+}
+function processChildContext(instance, type, parentContext, childContextTypes) {
+ {
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
+ if (typeof instance.getChildContext !== 'function') {
+
+ return parentContext;
+ }
+
+ const childContext = instance.getChildContext();
+
+ for (const contextKey in childContext) {
+ if (!(contextKey in childContextTypes)) {
+ throw Error(formatProdErrorMessage(108, getComponentNameFromType(type) || 'Unknown', contextKey));
+ }
+ }
+
+ return assign({}, parentContext, childContext);
+ }
+}
+
+// Forming a reverse tree.
+// The structure of a context snapshot is an implementation of this file.
+// Currently, it's implemented as tracking the current active node.
+
+
+const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
+// This global (actually thread local) state represents what state all those "current",
+// fields are currently in.
+
+let currentActiveSnapshot = null;
+
+function popNode(prev) {
+ {
+ prev.context._currentValue = prev.parentValue;
+ }
+}
+
+function pushNode(next) {
+ {
+ next.context._currentValue = next.value;
+ }
+}
+
+function popToNearestCommonAncestor(prev, next) {
+ if (prev === next) ; else {
+ popNode(prev);
+ const parentPrev = prev.parent;
+ const parentNext = next.parent;
+
+ if (parentPrev === null) {
+ if (parentNext !== null) {
+ throw Error(formatProdErrorMessage(401));
+ }
+ } else {
+ if (parentNext === null) {
+ throw Error(formatProdErrorMessage(401));
+ }
+
+ popToNearestCommonAncestor(parentPrev, parentNext);
+ } // On the way back, we push the new ones that weren't common.
+
+
+ pushNode(next);
+ }
+}
+
+function popAllPrevious(prev) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev !== null) {
+ popAllPrevious(parentPrev);
+ }
+}
+
+function pushAllNext(next) {
+ const parentNext = next.parent;
+
+ if (parentNext !== null) {
+ pushAllNext(parentNext);
+ }
+
+ pushNode(next);
+}
+
+function popPreviousToCommonLevel(prev, next) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev === null) {
+ throw Error(formatProdErrorMessage(402));
+ }
+
+ if (parentPrev.depth === next.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(parentPrev, next);
+ } else {
+ // We must still be deeper.
+ popPreviousToCommonLevel(parentPrev, next);
+ }
+}
+
+function popNextToCommonLevel(prev, next) {
+ const parentNext = next.parent;
+
+ if (parentNext === null) {
+ throw Error(formatProdErrorMessage(402));
+ }
+
+ if (prev.depth === parentNext.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(prev, parentNext);
+ } else {
+ // We must still be deeper.
+ popNextToCommonLevel(prev, parentNext);
+ }
+
+ pushNode(next);
+} // Perform context switching to the new snapshot.
+// To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
+// updating all the context's current values. That way reads, always just read the current value.
+// At the cost of updating contexts even if they're never read by this subtree.
+
+
+function switchContext(newSnapshot) {
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
+ // We also need to update any new contexts that are now on the stack with the deepest value.
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
+ // for that. Therefore this algorithm is recursive.
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
+ // 3) Then we reapply new contexts on the way back up the stack.
+ const prev = currentActiveSnapshot;
+ const next = newSnapshot;
+
+ if (prev !== next) {
+ if (prev === null) {
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
+ pushAllNext(next);
+ } else if (next === null) {
+ popAllPrevious(prev);
+ } else if (prev.depth === next.depth) {
+ popToNearestCommonAncestor(prev, next);
+ } else if (prev.depth > next.depth) {
+ popPreviousToCommonLevel(prev, next);
+ } else {
+ popNextToCommonLevel(prev, next);
+ }
+
+ currentActiveSnapshot = next;
+ }
+}
+function pushProvider(context, nextValue) {
+ let prevValue;
+
+ {
+ prevValue = context._currentValue;
+ context._currentValue = nextValue;
+ }
+
+ const prevNode = currentActiveSnapshot;
+ const newNode = {
+ parent: prevNode,
+ depth: prevNode === null ? 0 : prevNode.depth + 1,
+ context: context,
+ parentValue: prevValue,
+ value: nextValue
+ };
+ currentActiveSnapshot = newNode;
+ return newNode;
+}
+function popProvider(context) {
+ const prevSnapshot = currentActiveSnapshot;
+
+ if (prevSnapshot === null) {
+ throw Error(formatProdErrorMessage(403));
+ }
+
+ {
+ const value = prevSnapshot.parentValue;
+
+ if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) {
+ prevSnapshot.context._currentValue = prevSnapshot.context._defaultValue;
+ } else {
+ prevSnapshot.context._currentValue = value;
+ }
+ }
+
+ return currentActiveSnapshot = prevSnapshot.parent;
+}
+function getActiveContext() {
+ return currentActiveSnapshot;
+}
+function readContext$1(context) {
+ const value = context._currentValue ;
+ return value;
+}
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ *
+ * Note that this module is currently shared and assumed to be stateless.
+ * If this becomes an actual Map, that will break.
+ */
+function get(key) {
+ return key._reactInternals;
+}
+function set(key, value) {
+ key._reactInternals = value;
+}
+
+const classComponentUpdater = {
+ isMounted(inst) {
+ return false;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueSetState(inst, payload, callback) {
+ const internals = get(inst);
+
+ if (internals.queue === null) ; else {
+ internals.queue.push(payload);
+ }
+ },
+
+ enqueueReplaceState(inst, payload, callback) {
+ const internals = get(inst);
+ internals.replace = true;
+ internals.queue = [payload];
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueForceUpdate(inst, callback) {
+ }
+
+};
+
+function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) {
+ const partialState = getDerivedStateFromProps(nextProps, prevState);
+
+
+ const newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);
+ return newState;
+}
+
+function constructClassInstance(ctor, props, maskedLegacyContext) {
+ let context = emptyContextObject;
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ context = readContext$1(contextType);
+ } else {
+ context = maskedLegacyContext;
+ }
+
+ const instance = new ctor(props, context);
+
+ return instance;
+}
+
+function callComponentWillMount(type, instance) {
+ const oldState = instance.state;
+
+ if (typeof instance.componentWillMount === 'function') {
+
+ instance.componentWillMount();
+ }
+
+ if (typeof instance.UNSAFE_componentWillMount === 'function') {
+ instance.UNSAFE_componentWillMount();
+ }
+
+ if (oldState !== instance.state) {
+
+ classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
+ }
+}
+
+function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) {
+ if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
+ const oldQueue = internalInstance.queue;
+ const oldReplace = internalInstance.replace;
+ internalInstance.queue = null;
+ internalInstance.replace = false;
+
+ if (oldReplace && oldQueue.length === 1) {
+ inst.state = oldQueue[0];
+ } else {
+ let nextState = oldReplace ? oldQueue[0] : inst.state;
+ let dontMutate = true;
+
+ for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
+ const partial = oldQueue[i];
+ const partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial;
+
+ if (partialState != null) {
+ if (dontMutate) {
+ dontMutate = false;
+ nextState = assign({}, nextState, partialState);
+ } else {
+ assign(nextState, partialState);
+ }
+ }
+ }
+
+ inst.state = nextState;
+ }
+ } else {
+ internalInstance.queue = null;
+ }
+} // Invokes the mount life-cycles on a previously never rendered instance.
+
+
+function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) {
+
+ const initialState = instance.state !== undefined ? instance.state : null;
+ instance.updater = classComponentUpdater;
+ instance.props = newProps;
+ instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway.
+ // The internal instance will be used to manage updates that happen during this mount.
+
+ const internalInstance = {
+ queue: [],
+ replace: false
+ };
+ set(instance, internalInstance);
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ instance.context = readContext$1(contextType);
+ } else {
+ instance.context = maskedLegacyContext;
+ }
+
+ const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
+
+ if (typeof getDerivedStateFromProps === 'function') {
+ instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps);
+ } // In order to support react-lifecycles-compat polyfilled components,
+ // Unsafe lifecycles should not be invoked for components using the new APIs.
+
+
+ if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
+ callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's
+ // process them now.
+
+ processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext);
+ }
+}
+
+// Ids are base 32 strings whose binary representation corresponds to the
+// position of a node in a tree.
+// Every time the tree forks into multiple children, we add additional bits to
+// the left of the sequence that represent the position of the child within the
+// current level of children.
+//
+// 00101 00010001011010101
+// ╰─┬─╯ ╰───────┬───────╯
+// Fork 5 of 20 Parent id
+//
+// The leading 0s are important. In the above example, you only need 3 bits to
+// represent slot 5. However, you need 5 bits to represent all the forks at
+// the current level, so we must account for the empty bits at the end.
+//
+// For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise,
+// the zeroth id at a level would be indistinguishable from its parent.
+//
+// If a node has only one child, and does not materialize an id (i.e. does not
+// contain a useId hook), then we don't need to allocate any space in the
+// sequence. It's treated as a transparent indirection. For example, these two
+// trees produce the same ids:
+//
+// <> <>
+//
+//
+// >
+//
+// >
+//
+// However, we cannot skip any node that materializes an id. Otherwise, a parent
+// id that does not fork would be indistinguishable from its child id. For
+// example, this tree does not fork, but the parent and child must have
+// different ids.
+//
+//
+//
+//
+//
+// To handle this scenario, every time we materialize an id, we allocate a
+// new level with a single slot. You can think of this as a fork with only one
+// prong, or an array of children with length 1.
+//
+// It's possible for the size of the sequence to exceed 32 bits, the max
+// size for bitwise operations. When this happens, we make more room by
+// converting the right part of the id to a string and storing it in an overflow
+// variable. We use a base 32 string representation, because 32 is the largest
+// power of 2 that is supported by toString(). We want the base to be large so
+// that the resulting ids are compact, and we want the base to be a power of 2
+// because every log2(base) bits corresponds to a single character, i.e. every
+// log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without
+// affecting the final result.
+const emptyTreeContext = {
+ id: 1,
+ overflow: ''
+};
+function getTreeId(context) {
+ const overflow = context.overflow;
+ const idWithLeadingBit = context.id;
+ const id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);
+ return id.toString(32) + overflow;
+}
+function pushTreeContext(baseContext, totalChildren, index) {
+ const baseIdWithLeadingBit = baseContext.id;
+ const baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part
+ // of the id; we use it to account for leading 0s.
+
+ const baseLength = getBitLength(baseIdWithLeadingBit) - 1;
+ const baseId = baseIdWithLeadingBit & ~(1 << baseLength);
+ const slot = index + 1;
+ const length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into
+ // consideration the leading 1 we use to mark the end of the sequence.
+
+ if (length > 30) {
+ // We overflowed the bitwise-safe range. Fall back to slower algorithm.
+ // This branch assumes the length of the base id is greater than 5; it won't
+ // work for smaller ids, because you need 5 bits per character.
+ //
+ // We encode the id in multiple steps: first the base id, then the
+ // remaining digits.
+ //
+ // Each 5 bit sequence corresponds to a single base 32 character. So for
+ // example, if the current id is 23 bits long, we can convert 20 of those
+ // bits into a string of 4 characters, with 3 bits left over.
+ //
+ // First calculate how many bits in the base id represent a complete
+ // sequence of characters.
+ const numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.
+
+ const newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.
+
+ const newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.
+
+ const restOfBaseId = baseId >> numberOfOverflowBits;
+ const restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because
+ // we made more room, this time it won't overflow.
+
+ const restOfLength = getBitLength(totalChildren) + restOfBaseLength;
+ const restOfNewBits = slot << restOfBaseLength;
+ const id = restOfNewBits | restOfBaseId;
+ const overflow = newOverflow + baseOverflow;
+ return {
+ id: 1 << restOfLength | id,
+ overflow
+ };
+ } else {
+ // Normal path
+ const newBits = slot << baseLength;
+ const id = newBits | baseId;
+ const overflow = baseOverflow;
+ return {
+ id: 1 << length | id,
+ overflow
+ };
+ }
+}
+
+function getBitLength(number) {
+ return 32 - clz32(number);
+}
+
+function getLeadingBit(id) {
+ return 1 << getBitLength(id) - 1;
+} // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback.
+
+
+const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.
+// Based on:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+const log = Math.log;
+const LN2 = Math.LN2;
+
+function clz32Fallback(x) {
+ const asUint = x >>> 0;
+
+ if (asUint === 0) {
+ return 32;
+ }
+
+ return 31 - (log(asUint) / LN2 | 0) | 0;
+}
+
+// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
+// changes to one module should be reflected in the others.
+// TODO: Rename this module and the corresponding Fiber one to "Thenable"
+// instead of "Wakeable". Or some other more appropriate name.
+// An error that is thrown (e.g. by `use`) to trigger Suspense. If we
+// detect this is caught by userspace, we'll log a warning in development.
+const SuspenseException = Error(formatProdErrorMessage(460));
+function createThenableState() {
+ // The ThenableState is created the first time a component suspends. If it
+ // suspends again, we'll reuse the same state.
+ return [];
+}
+
+function noop$2() {}
+
+function trackUsedThenable(thenableState, thenable, index) {
+ const previous = thenableState[index];
+
+ if (previous === undefined) {
+ thenableState.push(thenable);
+ } else {
+ if (previous !== thenable) {
+ // Reuse the previous thenable, and drop the new one. We can assume
+ // they represent the same value, because components are idempotent.
+ // Avoid an unhandled rejection errors for the Promises that we'll
+ // intentionally ignore.
+ thenable.then(noop$2, noop$2);
+ thenable = previous;
+ }
+ } // We use an expando to track the status and result of a thenable so that we
+ // can synchronously unwrap the value. Think of this as an extension of the
+ // Promise API, or a custom interface that is a superset of Thenable.
+ //
+ // If the thenable doesn't have a status, set it to "pending" and attach
+ // a listener that will update its status and result when it resolves.
+
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledValue = thenable.value;
+ return fulfilledValue;
+ }
+
+ case 'rejected':
+ {
+ const rejectedError = thenable.reason;
+ throw rejectedError;
+ }
+
+ default:
+ {
+ if (typeof thenable.status === 'string') ; else {
+ const pendingThenable = thenable;
+ pendingThenable.status = 'pending';
+ pendingThenable.then(fulfilledValue => {
+ if (thenable.status === 'pending') {
+ const fulfilledThenable = thenable;
+ fulfilledThenable.status = 'fulfilled';
+ fulfilledThenable.value = fulfilledValue;
+ }
+ }, error => {
+ if (thenable.status === 'pending') {
+ const rejectedThenable = thenable;
+ rejectedThenable.status = 'rejected';
+ rejectedThenable.reason = error;
+ }
+ }); // Check one more time in case the thenable resolved synchronously
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledThenable = thenable;
+ return fulfilledThenable.value;
+ }
+
+ case 'rejected':
+ {
+ const rejectedThenable = thenable;
+ throw rejectedThenable.reason;
+ }
+ }
+ } // Suspend.
+ //
+ // Throwing here is an implementation detail that allows us to unwind the
+ // call stack. But we shouldn't allow it to leak into userspace. Throw an
+ // opaque placeholder value instead of the actual thenable. If it doesn't
+ // get captured by the work loop, log a warning, because that means
+ // something in userspace must have caught it.
+
+
+ suspendedThenable = thenable;
+ throw SuspenseException;
+ }
+ }
+} // This is used to track the actual thenable that suspended so it can be
+// passed to the rest of the Suspense implementation — which, for historical
+// reasons, expects to receive a thenable.
+
+let suspendedThenable = null;
+function getSuspendedThenable() {
+ // This is called right after `use` suspends by throwing an exception. `use`
+ // throws an opaque value instead of the thenable itself so that it can't be
+ // caught in userspace. Then the work loop accesses the actual thenable using
+ // this function.
+ if (suspendedThenable === null) {
+ throw Error(formatProdErrorMessage(459));
+ }
+
+ const thenable = suspendedThenable;
+ suspendedThenable = null;
+ return thenable;
+}
+
+/**
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+ */
+function is(x, y) {
+ return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
+ ;
+}
+
+const objectIs = // $FlowFixMe[method-unbinding]
+typeof Object.is === 'function' ? Object.is : is;
+
+let currentlyRenderingComponent = null;
+let currentlyRenderingTask = null;
+let currentlyRenderingRequest = null;
+let currentlyRenderingKeyPath = null;
+let firstWorkInProgressHook = null;
+let workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook
+
+let isReRender = false; // Whether an update was scheduled during the currently executing render pass.
+
+let didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component
+
+let localIdCounter = 0; // Chunks that should be pushed to the stream once the component
+// finishes rendering.
+// Counts the number of useFormState calls in this component
+
+let formStateCounter = 0; // The index of the useFormState hook that matches the one passed in at the
+// root during an MPA navigation, if any.
+
+let formStateMatchingIndex = -1; // Counts the number of use(thenable) calls in this component
+
+let thenableIndexCounter = 0;
+let thenableState = null; // Lazily created map of render-phase updates
+
+let renderPhaseUpdates = null; // Counter to prevent infinite loops.
+
+let numberOfReRenders = 0;
+const RE_RENDER_LIMIT = 25;
+
+function resolveCurrentlyRenderingComponent() {
+ if (currentlyRenderingComponent === null) {
+ throw Error(formatProdErrorMessage(321));
+ }
+
+ return currentlyRenderingComponent;
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+
+ return false;
+ }
+
+
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ if (objectIs(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+function createHook() {
+ if (numberOfReRenders > 0) {
+ throw Error(formatProdErrorMessage(312));
+ }
+
+ return {
+ memoizedState: null,
+ queue: null,
+ next: null
+ };
+}
+
+function createWorkInProgressHook() {
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ if (firstWorkInProgressHook === null) {
+ isReRender = false;
+ firstWorkInProgressHook = workInProgressHook = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = firstWorkInProgressHook;
+ }
+ } else {
+ if (workInProgressHook.next === null) {
+ isReRender = false; // Append to the end of the list
+
+ workInProgressHook = workInProgressHook.next = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = workInProgressHook.next;
+ }
+ }
+
+ return workInProgressHook;
+}
+
+function prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState) {
+ currentlyRenderingComponent = componentIdentity;
+ currentlyRenderingTask = task;
+ currentlyRenderingRequest = request;
+ currentlyRenderingKeyPath = keyPath;
+ // didScheduleRenderPhaseUpdate = false;
+ // firstWorkInProgressHook = null;
+ // numberOfReRenders = 0;
+ // renderPhaseUpdates = null;
+ // workInProgressHook = null;
+
+
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ thenableState = prevThenableState;
+}
+function finishHooks(Component, props, children, refOrContext) {
+ // This must be called after every function component to prevent hooks from
+ // being used in classes.
+ while (didScheduleRenderPhaseUpdate) {
+ // Updates were scheduled during the render phase. They are stored in
+ // the `renderPhaseUpdates` map. Call the component again, reusing the
+ // work-in-progress hooks and applying the additional updates on top. Keep
+ // restarting until no more updates are scheduled.
+ didScheduleRenderPhaseUpdate = false;
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ numberOfReRenders += 1; // Start over from the beginning of the list
+
+ workInProgressHook = null;
+ children = Component(props, refOrContext);
+ }
+
+ resetHooksState();
+ return children;
+}
+function getThenableStateAfterSuspending() {
+ const state = thenableState;
+ thenableState = null;
+ return state;
+}
+function checkDidRenderIdHook() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ const didRenderIdHook = localIdCounter !== 0;
+ return didRenderIdHook;
+}
+function getFormStateCount() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateCounter;
+}
+function getFormStateMatchingIndex() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateMatchingIndex;
+} // Reset the internal hooks state if an error occurs while rendering a component
+
+function resetHooksState() {
+
+ currentlyRenderingComponent = null;
+ currentlyRenderingTask = null;
+ currentlyRenderingRequest = null;
+ currentlyRenderingKeyPath = null;
+ didScheduleRenderPhaseUpdate = false;
+ firstWorkInProgressHook = null;
+ numberOfReRenders = 0;
+ renderPhaseUpdates = null;
+ workInProgressHook = null;
+}
+
+function readContext(context) {
+
+ return readContext$1(context);
+}
+
+function useContext(context) {
+
+ resolveCurrentlyRenderingComponent();
+ return readContext$1(context);
+}
+
+function basicStateReducer(state, action) {
+ // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
+ return typeof action === 'function' ? action(state) : action;
+}
+
+function useState(initialState) {
+
+ return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers
+ initialState);
+}
+function useReducer(reducer, initialArg, init) {
+
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+
+ if (isReRender) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ // current hook.
+ const queue = workInProgressHook.queue;
+ const dispatch = queue.dispatch;
+
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate !== undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.delete(queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ let newState = workInProgressHook.memoizedState;
+ let update = firstRenderPhaseUpdate;
+
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ const action = update.action;
+
+ newState = reducer(newState, action);
+
+
+ update = update.next;
+ } while (update !== null); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ workInProgressHook.memoizedState = newState;
+ return [newState, dispatch];
+ }
+ } // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ return [workInProgressHook.memoizedState, dispatch];
+ } else {
+
+ let initialState;
+
+ if (reducer === basicStateReducer) {
+ // Special case for `useState`.
+ initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
+ } else {
+ initialState = init !== undefined ? init(initialArg) : initialArg;
+ }
+
+
+ workInProgressHook.memoizedState = initialState; // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ const queue = workInProgressHook.queue = {
+ last: null,
+ dispatch: null
+ };
+ const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ return [workInProgressHook.memoizedState, dispatch];
+ }
+}
+
+function useMemo(nextCreate, deps) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const nextDeps = deps === undefined ? null : deps;
+
+ if (workInProgressHook !== null) {
+ const prevState = workInProgressHook.memoizedState;
+
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ const prevDeps = prevState[1];
+
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ }
+
+ const nextValue = nextCreate();
+
+
+ workInProgressHook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function useRef(initialValue) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const previousRef = workInProgressHook.memoizedState;
+
+ if (previousRef === null) {
+ const ref = {
+ current: initialValue
+ };
+
+
+ workInProgressHook.memoizedState = ref;
+ return ref;
+ } else {
+ return previousRef;
+ }
+}
+
+function dispatchAction(componentIdentity, queue, action) {
+ if (numberOfReRenders >= RE_RENDER_LIMIT) {
+ throw Error(formatProdErrorMessage(301));
+ }
+
+ if (componentIdentity === currentlyRenderingComponent) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ const update = {
+ action,
+ next: null
+ };
+
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate === undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+
+ lastRenderPhaseUpdate.next = update;
+ }
+ }
+}
+
+function useCallback(callback, deps) {
+ return useMemo(() => callback, deps);
+}
+
+function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
+ if (getServerSnapshot === undefined) {
+ throw Error(formatProdErrorMessage(407));
+ }
+
+ return getServerSnapshot();
+}
+
+function useDeferredValue(value, initialValue) {
+ resolveCurrentlyRenderingComponent();
+
+ {
+ return value;
+ }
+}
+
+function unsupportedStartTransition() {
+ throw Error(formatProdErrorMessage(394));
+}
+
+function useTransition() {
+ resolveCurrentlyRenderingComponent();
+ return [false, unsupportedStartTransition];
+}
+
+function useHostTransitionStatus() {
+ resolveCurrentlyRenderingComponent();
+ return NotPendingTransition;
+}
+
+function unsupportedSetOptimisticState() {
+ throw Error(formatProdErrorMessage(479));
+}
+
+function useOptimistic(passthrough, reducer) {
+ resolveCurrentlyRenderingComponent();
+ return [passthrough, unsupportedSetOptimisticState];
+}
+
+function createPostbackFormStateKey(permalink, componentKeyPath, hookIndex) {
+ if (permalink !== undefined) {
+ // Don't bother to hash a permalink-based key since it's already short.
+ return 'p' + permalink;
+ } else {
+ // Append a node to the key path that represents the form state hook.
+ const keyPath = [componentKeyPath, null, hookIndex]; // Key paths are hashed to reduce the size. It does not need to be secure,
+ // and it's more important that it's fast than that it's completely
+ // collision-free.
+
+ const keyPathHash = createFastHashJS(JSON.stringify(keyPath));
+ return 'k' + keyPathHash;
+ }
+}
+
+function useFormState(action, initialState, permalink) {
+ resolveCurrentlyRenderingComponent(); // Count the number of useFormState hooks per component. We also use this to
+ // track the position of this useFormState hook relative to the other ones in
+ // this component, so we can generate a unique key for each one.
+
+ const formStateHookIndex = formStateCounter++;
+ const request = currentlyRenderingRequest; // $FlowIgnore[prop-missing]
+
+ const formAction = action.$$FORM_ACTION;
+
+ if (typeof formAction === 'function') {
+ // This is a server action. These have additional features to enable
+ // MPA-style form submissions with progressive enhancement.
+ // TODO: If the same permalink is passed to multiple useFormStates, and
+ // they all have the same action signature, Fizz will pass the postback
+ // state to all of them. We should probably only pass it to the first one,
+ // and/or warn.
+ // The key is lazily generated and deduped so the that the keypath doesn't
+ // get JSON.stringify-ed unnecessarily, and at most once.
+ let nextPostbackStateKey = null; // Determine the current form state. If we received state during an MPA form
+ // submission, then we will reuse that, if the action identity matches.
+ // Otherwise we'll use the initial state argument. We will emit a comment
+ // marker into the stream that indicates whether the state was reused.
+
+ let state = initialState;
+ const componentKeyPath = currentlyRenderingKeyPath;
+ const postbackFormState = getFormState(request); // $FlowIgnore[prop-missing]
+
+ const isSignatureEqual = action.$$IS_SIGNATURE_EQUAL;
+
+ if (postbackFormState !== null && typeof isSignatureEqual === 'function') {
+ const postbackKey = postbackFormState[1];
+ const postbackReferenceId = postbackFormState[2];
+ const postbackBoundArity = postbackFormState[3];
+
+ if (isSignatureEqual.call(action, postbackReferenceId, postbackBoundArity)) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+
+ if (postbackKey === nextPostbackStateKey) {
+ // This was a match
+ formStateMatchingIndex = formStateHookIndex; // Reuse the state that was submitted by the form.
+
+ state = postbackFormState[0];
+ }
+ }
+ } // Bind the state to the first argument of the action.
+
+
+ const boundAction = action.bind(null, state); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ }; // $FlowIgnore[prop-missing]
+
+
+ if (typeof boundAction.$$FORM_ACTION === 'function') {
+ // $FlowIgnore[prop-missing]
+ dispatch.$$FORM_ACTION = prefix => {
+ const metadata = boundAction.$$FORM_ACTION(prefix); // Override the action URL
+
+ if (permalink !== undefined) {
+
+ permalink += '';
+ metadata.action = permalink;
+ }
+
+ const formData = metadata.data;
+
+ if (formData) {
+ if (nextPostbackStateKey === null) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+ }
+
+ formData.append('$ACTION_KEY', nextPostbackStateKey);
+ }
+
+ return metadata;
+ };
+ }
+
+ return [state, dispatch];
+ } else {
+ // This is not a server action, so the implementation is much simpler.
+ // Bind the state to the first argument of the action.
+ const boundAction = action.bind(null, initialState); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ };
+
+ return [initialState, dispatch];
+ }
+}
+
+function useId() {
+ const task = currentlyRenderingTask;
+ const treeId = getTreeId(task.treeContext);
+ const resumableState = currentResumableState;
+
+ if (resumableState === null) {
+ throw Error(formatProdErrorMessage(404));
+ }
+
+ const localId = localIdCounter++;
+ return makeId(resumableState, treeId, localId);
+}
+
+function use(usable) {
+ if (usable !== null && typeof usable === 'object') {
+ // $FlowFixMe[method-unbinding]
+ if (typeof usable.then === 'function') {
+ // This is a thenable.
+ const thenable = usable;
+ return unwrapThenable(thenable);
+ } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = usable;
+ return readContext(context);
+ }
+ } // eslint-disable-next-line react-internal/safe-string-coercion
+
+
+ throw Error(formatProdErrorMessage(438, String(usable)));
+}
+
+function unwrapThenable(thenable) {
+ const index = thenableIndexCounter;
+ thenableIndexCounter += 1;
+
+ if (thenableState === null) {
+ thenableState = createThenableState();
+ }
+
+ return trackUsedThenable(thenableState, thenable, index);
+}
+
+function unsupportedRefresh() {
+ throw Error(formatProdErrorMessage(393));
+}
+
+function useCacheRefresh() {
+ return unsupportedRefresh;
+}
+
+function noop$1() {}
+
+const HooksDispatcher = {
+ readContext,
+ use,
+ useContext,
+ useMemo,
+ useReducer,
+ useRef,
+ useState,
+ useInsertionEffect: noop$1,
+ useLayoutEffect: noop$1,
+ useCallback,
+ // useImperativeHandle is not run in the server environment
+ useImperativeHandle: noop$1,
+ // Effects are not run in the server environment.
+ useEffect: noop$1,
+ // Debugging effect
+ useDebugValue: noop$1,
+ useDeferredValue,
+ useTransition,
+ useId,
+ // Subscriptions are not setup in a server environment.
+ useSyncExternalStore
+};
+
+{
+ HooksDispatcher.useCacheRefresh = useCacheRefresh;
+}
+
+{
+ HooksDispatcher.useHostTransitionStatus = useHostTransitionStatus;
+}
+
+{
+ HooksDispatcher.useOptimistic = useOptimistic;
+ HooksDispatcher.useFormState = useFormState;
+}
+
+let currentResumableState = null;
+function setCurrentResumableState(resumableState) {
+ currentResumableState = resumableState;
+}
+
+function getCacheSignal() {
+ throw Error(formatProdErrorMessage(248));
+}
+
+function getCacheForType(resourceType) {
+ throw Error(formatProdErrorMessage(248));
+}
+
+const DefaultCacheDispatcher = {
+ getCacheSignal,
+ getCacheForType
+};
+
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
+const ReactCurrentCache = ReactSharedInternals.ReactCurrentCache;
+// The name might be minified but we assume that it's going to be the same generated name. Typically
+// because it's just the same compiled output in practice.
+// resume with segmentID at the index
+
+const CLIENT_RENDERED = 4; // if it errors or infinitely suspends
+
+const PENDING = 0;
+const COMPLETED = 1;
+const FLUSHED = 2;
+const ABORTED = 3;
+const ERRORED = 4;
+const POSTPONED = 5;
+const OPEN = 0;
+const CLOSING = 1;
+const CLOSED = 2; // This is a default heuristic for how to split up the HTML content into progressive
+// loading. Our goal is to be able to display additional new content about every 500ms.
+// Faster than that is unnecessary and should be throttled on the client. It also
+// adds unnecessary overhead to do more splits. We don't know if it's a higher or lower
+// end device but higher end suffer less from the overhead than lower end does from
+// not getting small enough pieces. We error on the side of low end.
+// We base this on low end 3G speeds which is about 500kbits per second. We assume
+// that there can be a reasonable drop off from max bandwidth which leaves you with
+// as little as 80%. We can receive half of that each 500ms - at best. In practice,
+// a little bandwidth is lost to processing and contention - e.g. CSS and images that
+// are downloaded along with the main content. So we estimate about half of that to be
+// the lower end throughput. In other words, we expect that you can at least show
+// about 12.5kb of content per 500ms. Not counting starting latency for the first
+// paint.
+// 500 * 1024 / 8 * .8 * 0.5 / 2
+
+const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
+
+function defaultErrorHandler(error) {
+ console['error'](error); // Don't transform to our wrapper
+
+ return null;
+}
+
+function noop() {}
+
+function createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, formState) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState,
+ renderState,
+ rootFormatContext,
+ progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: 0,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: formState === undefined ? null : formState
+ }; // This segment represents the root fallback.
+
+ const rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false); // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+let currentRequest = null;
+function resolveRequest() {
+ if (currentRequest) return currentRequest;
+
+ return null;
+}
+
+function pingTask(request, task) {
+ const pingedTasks = request.pingedTasks;
+ pingedTasks.push(task);
+
+ if (request.pingedTasks.length === 1) {
+ request.flushScheduled = request.destination !== null;
+ scheduleWork(() => performWork(request));
+ }
+}
+
+function createSuspenseBoundary(request, fallbackAbortableTasks) {
+ return {
+ status: PENDING,
+ rootSegmentID: -1,
+ parentFlushed: false,
+ pendingTasks: 0,
+ completedSegments: [],
+ byteSize: 0,
+ fallbackAbortableTasks,
+ errorDigest: null,
+ resources: createBoundaryResources(),
+ trackedContentKeyPath: null,
+ trackedFallbackNode: null
+ };
+}
+
+function createRenderTask(request, thenableState, node, childIndex, blockedBoundary, blockedSegment, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ const task = {
+ replay: null,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createReplayTask(request, thenableState, replay, node, childIndex, blockedBoundary, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ replay.pendingTasks++;
+ const task = {
+ replay,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment: null,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createPendingSegment(request, index, boundary, parentFormatContext, lastPushedText, textEmbedded) {
+ return {
+ status: PENDING,
+ id: -1,
+ // lazily assigned later
+ index,
+ parentFlushed: false,
+ chunks: [],
+ children: [],
+ parentFormatContext,
+ boundary,
+ lastPushedText,
+ textEmbedded
+ };
+} // DEV-only global reference to the currently executing task
+
+function popComponentStackInDEV(task) {
+} // stash the component stack of an unwinding error until it is processed
+
+function logRecoverableError(request, error) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ const errorDigest = request.onError(error);
+
+ if (errorDigest != null && typeof errorDigest !== 'string') {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead");
+ }
+
+ return errorDigest;
+}
+
+function fatalError(request, error) {
+ // This is called outside error handling code such as if the root errors outside
+ // a suspense boundary or if the root suspense boundary's fallback errors.
+ // It's also called if React itself or its host configs errors.
+ const onShellError = request.onShellError;
+ onShellError(error);
+ const onFatalError = request.onFatalError;
+ onFatalError(error);
+
+ if (request.destination !== null) {
+ request.status = CLOSED;
+ closeWithError(request.destination, error);
+ } else {
+ request.status = CLOSING;
+ request.fatalError = error;
+ }
+}
+
+function renderSuspenseBoundary(request, someTask, keyPath, props) {
+ if (someTask.replay !== null) {
+ // If we're replaying through this pass, it means we're replaying through
+ // an already completed Suspense boundary. It's too late to do anything about it
+ // so we can just render through it.
+ const prevKeyPath = someTask.keyPath;
+ someTask.keyPath = keyPath;
+ const content = props.children;
+
+ try {
+ renderNode(request, someTask, content, -1);
+ } finally {
+ someTask.keyPath = prevKeyPath;
+ }
+
+ return;
+ } // $FlowFixMe: Refined.
+
+
+ const task = someTask;
+ const prevKeyPath = task.keyPath;
+ const parentBoundary = task.blockedBoundary;
+ const parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for
+ // the fallback so that we can later replace that segment with the content.
+ // This also lets us split out the main content even if it doesn't suspend,
+ // in case it ends up generating a large subtree of content.
+
+ const fallback = props.fallback;
+ const content = props.children;
+ const fallbackAbortSet = new Set();
+ const newBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+
+ if (request.trackedPostpones !== null) {
+ newBoundary.trackedContentKeyPath = keyPath;
+ }
+
+ const insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback.
+
+ const boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false);
+ parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent
+
+ parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately.
+
+ const contentRootSegment = createPendingSegment(request, 0, null, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is
+ // no parent segment so there's nothing to wait on.
+
+ contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks.
+ // I suspect that there might be some efficiency benefits from not creating the suspended task
+ // and instead just using the stack if possible.
+ // TODO: Call this directly instead of messing with saving and restoring contexts.
+ // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and which segment
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = newBoundary;
+ task.blockedSegment = contentRootSegment;
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, newBoundary.resources);
+ }
+
+ task.keyPath = keyPath;
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+ pushSegmentFinale(contentRootSegment.chunks, request.renderState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded);
+ contentRootSegment.status = COMPLETED;
+ queueCompletedSegment(newBoundary, contentRootSegment);
+
+ if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
+ newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ contentRootSegment.status = ERRORED;
+ newBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ newBoundary.errorDigest = errorDigest;
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.blockedSegment = parentSegment;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]];
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones !== null) {
+ // We create a detached replay node to track any postpones inside the fallback.
+ const fallbackReplayNode = [fallbackKeyPath[1], fallbackKeyPath[2], [], null];
+ trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
+
+ if (newBoundary.status === POSTPONED) {
+ // This must exist now.
+ const boundaryReplayNode = trackedPostpones.workingMap.get(keyPath);
+ boundaryReplayNode[4] = fallbackReplayNode;
+ } else {
+ // We might not inject it into the postponed tree, unless the content actually
+ // postpones too. We need to keep track of it until that happpens.
+ newBoundary.trackedFallbackNode = fallbackReplayNode;
+ }
+ } // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+
+ const suspendedFallbackTask = createRenderTask(request, null, fallback, -1, parentBoundary, boundarySegment, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function replaySuspenseBoundary(request, task, keyPath, props, id, childNodes, childSlots, fallbackNodes, fallbackSlots) {
+ const prevKeyPath = task.keyPath;
+ const previousReplaySet = task.replay;
+ const parentBoundary = task.blockedBoundary;
+ const content = props.children;
+ const fallback = props.fallback;
+ const fallbackAbortSet = new Set();
+ const resumedBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = id; // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and replay node
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = resumedBoundary;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, resumedBoundary.resources);
+ }
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+
+ if (resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING) {
+ resumedBoundary.status = COMPLETED;
+ request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ resumedBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ resumedBoundary.errorDigest = errorDigest;
+
+ task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted.
+
+ request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task.
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.replay = previousReplaySet;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+ const fallbackReplay = {
+ nodes: fallbackNodes,
+ slots: fallbackSlots,
+ pendingTasks: 0
+ };
+ const suspendedFallbackTask = createReplayTask(request, null, fallbackReplay, fallback, -1, parentBoundary, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function renderHostElement(request, task, keyPath, type, props) {
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ const children = props.children; // TODO: Make this a Config for replaying.
+
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ } else {
+ // Render
+ const children = pushStartInstance(segment.chunks, type, props, request.resumableState, request.renderState, task.formatContext, segment.lastPushedText);
+ segment.lastPushedText = false;
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ pushEndInstance(segment.chunks, type, props, request.resumableState, prevContext);
+ segment.lastPushedText = false;
+ }
+}
+
+function shouldConstruct(Component) {
+ return Component.prototype && Component.prototype.isReactComponent;
+}
+
+function renderWithHooks(request, task, keyPath, prevThenableState, Component, props, secondArg) {
+ const componentIdentity = {};
+ prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState);
+ const result = Component(props, secondArg);
+ return finishHooks(Component, props, result, secondArg);
+}
+
+function finishClassComponent(request, task, keyPath, instance, Component, props) {
+ const nextChildren = instance.render();
+
+ {
+ const childContextTypes = Component.childContextTypes;
+
+ if (childContextTypes !== null && childContextTypes !== undefined) {
+ const previousContext = task.legacyContext;
+ const mergedContext = processChildContext(instance, Component, previousContext, childContextTypes);
+ task.legacyContext = mergedContext;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.legacyContext = previousContext;
+ return;
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderClassComponent(request, task, keyPath, Component, props) {
+ const maskedContext = getMaskedContext(Component, task.legacyContext) ;
+ const instance = constructClassInstance(Component, props, maskedContext);
+ mountClassInstance(instance, Component, props, maskedContext);
+ finishClassComponent(request, task, keyPath, instance, Component);
+}
+// components for some reason.
+
+function renderIndeterminateComponent(request, task, keyPath, prevThenableState, Component, props) {
+ let legacyContext;
+
+ {
+ legacyContext = getMaskedContext(Component, task.legacyContext);
+ }
+
+ const value = renderWithHooks(request, task, keyPath, prevThenableState, Component, props, legacyContext);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+
+ if ( // Run these checks in production only if the flag is off.
+ // Eventually we'll delete this branch altogether.
+ typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
+
+ mountClassInstance(value, Component, props, legacyContext);
+ finishClassComponent(request, task, keyPath, value, Component);
+ } else {
+
+ finishFunctionComponent(request, task, keyPath, value, hasId, formStateCount, formStateMatchingIndex);
+ }
+}
+
+function finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex) {
+ let didEmitFormStateMarkers = false;
+
+ if (formStateCount !== 0 && request.formState !== null) {
+ // For each useFormState hook, emit a marker that indicates whether we
+ // rendered using the form state passed at the root. We only emit these
+ // markers if form state is passed at the root.
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ didEmitFormStateMarkers = true;
+ const target = segment.chunks;
+
+ for (let i = 0; i < formStateCount; i++) {
+ if (i === formStateMatchingIndex) {
+ pushFormStateMarkerIsMatching(target);
+ } else {
+ pushFormStateMarkerIsNotMatching(target);
+ }
+ }
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+
+ if (hasId) {
+ // This component materialized an id. We treat this as its own level, with
+ // a single "child" slot.
+ const prevTreeContext = task.treeContext;
+ const totalChildren = 1;
+ const index = 0; // Modify the id context. Because we'll need to reset this if something
+ // suspends or errors, we'll use the non-destructive render path.
+
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
+ renderNode(request, task, children, -1); // Like the other contexts, this does not need to be in a finally block
+ // because renderNode takes care of unwinding the stack.
+
+ task.treeContext = prevTreeContext;
+ } else if (didEmitFormStateMarkers) {
+ // If there were formState hooks, we must use the non-destructive path
+ // because this component is not a pure indirection; we emitted markers
+ // to the stream.
+ renderNode(request, task, children, -1);
+ } else {
+ // We're now successfully past this task, and we haven't modified the
+ // context stack. We don't have to pop back to the previous task every
+ // again, so we can use the destructive recursive form.
+ renderNodeDestructive(request, task, null, children, -1);
+ }
+
+ task.keyPath = prevKeyPath;
+}
+
+function resolveDefaultProps(Component, baseProps) {
+ if (Component && Component.defaultProps) {
+ // Resolve default props. Taken from ReactElement
+ const props = assign({}, baseProps);
+ const defaultProps = Component.defaultProps;
+
+ for (const propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+
+ return props;
+ }
+
+ return baseProps;
+}
+
+function renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref) {
+ const children = renderWithHooks(request, task, keyPath, prevThenableState, type.render, props, ref);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+ finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex);
+}
+
+function renderMemo(request, task, keyPath, prevThenableState, type, props, ref) {
+ const innerType = type.type;
+ const resolvedProps = resolveDefaultProps(innerType, props);
+ renderElement(request, task, keyPath, prevThenableState, innerType, resolvedProps, ref);
+}
+
+function renderContextConsumer(request, task, keyPath, context, props) {
+
+ const render = props.children;
+
+ const newValue = readContext$1(context);
+ const newChildren = render(newValue);
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, newChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderContextProvider(request, task, keyPath, type, props) {
+ const context = type._context;
+ const value = props.value;
+ const children = props.children;
+
+ const prevKeyPath = task.keyPath;
+ task.context = pushProvider(context, value);
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, children, -1);
+ task.context = popProvider();
+ task.keyPath = prevKeyPath;
+}
+
+function renderLazyComponent(request, task, keyPath, prevThenableState, lazyComponent, props, ref) {
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+ const Component = init(payload);
+ const resolvedProps = resolveDefaultProps(Component, props);
+ renderElement(request, task, keyPath, prevThenableState, Component, resolvedProps, ref);
+}
+
+function renderOffscreen(request, task, keyPath, props) {
+ const mode = props.mode;
+
+ if (mode === 'hidden') ; else {
+ // A visible Offscreen boundary is treated exactly like a fragment: a
+ // pure indirection.
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ }
+}
+
+function renderElement(request, task, keyPath, prevThenableState, type, props, ref) {
+ if (typeof type === 'function') {
+ if (shouldConstruct(type)) {
+ renderClassComponent(request, task, keyPath, type, props);
+ return;
+ } else {
+ renderIndeterminateComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+
+ if (typeof type === 'string') {
+ renderHostElement(request, task, keyPath, type, props);
+ return;
+ }
+
+ switch (type) {
+ // LegacyHidden acts the same as a fragment. This only works because we
+ // currently assume that every instance of LegacyHidden is accompanied by a
+ // host component wrapper. In the hidden mode, the host component is given a
+ // `hidden` attribute, which ensures that the initial HTML is not visible.
+ // To support the use of LegacyHidden as a true fragment, without an extra
+ // DOM node, we would have to hide the initial HTML in some other way.
+ // TODO: Delete in LegacyHidden. It's an unstable API only used in the
+ // www build. As a migration step, we could add a special prop to Offscreen
+ // that simulates the old behavior (no hiding, no change to effects).
+ case REACT_LEGACY_HIDDEN_TYPE:
+ case REACT_DEBUG_TRACING_MODE_TYPE:
+ case REACT_STRICT_MODE_TYPE:
+ case REACT_PROFILER_TYPE:
+ case REACT_FRAGMENT_TYPE:
+ {
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_OFFSCREEN_TYPE:
+ {
+ renderOffscreen(request, task, keyPath, props);
+ return;
+ }
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ {
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_SCOPE_TYPE:
+ {
+
+ throw Error(formatProdErrorMessage(343));
+ }
+
+ case REACT_SUSPENSE_TYPE:
+ {
+ {
+ renderSuspenseBoundary(request, task, keyPath, props);
+ }
+
+ return;
+ }
+ }
+
+ if (typeof type === 'object' && type !== null) {
+ switch (type.$$typeof) {
+ case REACT_FORWARD_REF_TYPE:
+ {
+ renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_MEMO_TYPE:
+ {
+ renderMemo(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_PROVIDER_TYPE:
+ {
+ renderContextProvider(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_CONTEXT_TYPE:
+ {
+ renderContextConsumer(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_LAZY_TYPE:
+ {
+ renderLazyComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+ }
+
+ let info = '';
+
+ throw Error(formatProdErrorMessage(130, type == null ? type : typeof type, info));
+}
+
+function resumeNode(request, task, segmentId, node, childIndex) {
+ const prevReplay = task.replay;
+ const blockedBoundary = task.blockedBoundary;
+ const resumedSegment = createPendingSegment(request, 0, null, task.formatContext, false, false);
+ resumedSegment.id = segmentId;
+ resumedSegment.parentFlushed = true;
+
+ try {
+ // Convert the current ReplayTask to a RenderTask.
+ const renderTask = task;
+ renderTask.replay = null;
+ renderTask.blockedSegment = resumedSegment;
+ renderNode(request, task, node, childIndex);
+ resumedSegment.status = COMPLETED;
+
+ if (blockedBoundary === null) {
+ request.completedRootSegment = resumedSegment;
+ } else {
+ queueCompletedSegment(blockedBoundary, resumedSegment);
+
+ if (blockedBoundary.parentFlushed) {
+ request.partialBoundaries.push(blockedBoundary);
+ }
+ }
+ } finally {
+ // Restore to a ReplayTask.
+ task.replay = prevReplay;
+ task.blockedSegment = null;
+ }
+}
+
+function replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, replay) {
+ // We're replaying. Find the path to follow.
+ const replayNodes = replay.nodes;
+
+ for (let i = 0; i < replayNodes.length; i++) {
+ // Flow doesn't support refinement on tuples so we do it manually here.
+ const node = replayNodes[i];
+
+ if (keyOrIndex !== node[1]) {
+ continue;
+ }
+
+ if (node.length === 4) {
+ // Matched a replayable path.
+ // Let's double check that the component name matches as a precaution.
+ if (name !== null && name !== node[0]) {
+ throw Error(formatProdErrorMessage(490, node[0], name));
+ }
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ const currentNode = task.node;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0 // TODO check remaining slots
+ ) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ if (task.node === currentNode) {
+ // This same element suspended so we need to pop the replay we just added.
+ task.replay = replay;
+ }
+
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay;
+ } else {
+ // Let's double check that the component type matches.
+ if (type !== REACT_SUSPENSE_TYPE) {
+ const expectedType = 'Suspense';
+ throw Error(formatProdErrorMessage(490, expectedType, getComponentNameFromType(type) || 'Unknown'));
+ } // Matched a replayable path.
+
+
+ replaySuspenseBoundary(request, task, keyPath, props, node[5], node[2], node[3], node[4] === null ? [] : node[4][2], node[4] === null ? null : node[4][3]);
+ } // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+
+ replayNodes.splice(i, 1);
+ return;
+ } // We didn't find any matching nodes. We assume that this element was already
+ // rendered in the prelude and skip it.
+
+} // $FlowFixMe[missing-local-annot]
+
+function renderNodeDestructive(request, task, // The thenable state reused from the previous attempt, if any. This is almost
+// always null, except when called by retryTask.
+prevThenableState, node, childIndex) {
+ {
+ return renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex);
+ }
+} // This function by it self renders a node and consumes the task by mutating it
+// to update the current execution state.
+
+
+function renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex) {
+ if (task.replay !== null && typeof task.replay.slots === 'number') {
+ // TODO: Figure out a cheaper place than this hot path to do this check.
+ const resumeSegmentID = task.replay.slots;
+ resumeNode(request, task, resumeSegmentID, node, childIndex);
+ return;
+ } // Stash the node we're working on. We'll pick up from this task in case
+ // something suspends.
+
+
+ task.node = node;
+ task.childIndex = childIndex; // Handle object types
+
+ if (typeof node === 'object' && node !== null) {
+ switch (node.$$typeof) {
+ case REACT_ELEMENT_TYPE:
+ {
+ const element = node;
+ const type = element.type;
+ const key = element.key;
+ const props = element.props;
+ const ref = element.ref;
+ const name = getComponentNameFromType(type);
+ const keyOrIndex = key == null ? childIndex === -1 ? 0 : childIndex : key;
+ const keyPath = [task.keyPath, name, keyOrIndex];
+
+ if (task.replay !== null) {
+ replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, task.replay); // No matches found for this node. We assume it's already emitted in the
+ // prelude and skip it during the replay.
+ } else {
+ // We're doing a plain render.
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+ }
+
+ return;
+ }
+
+ case REACT_PORTAL_TYPE:
+ throw Error(formatProdErrorMessage(257));
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyNode = node;
+ const payload = lazyNode._payload;
+ const init = lazyNode._init;
+ let resolvedNode;
+
+ {
+ resolvedNode = init(payload);
+ }
+
+ renderNodeDestructive(request, task, null, resolvedNode, childIndex);
+ return;
+ }
+ }
+
+ if (isArray(node)) {
+ renderChildrenArray(request, task, node, childIndex);
+ return;
+ }
+
+ const iteratorFn = getIteratorFn(node);
+
+ if (iteratorFn) {
+
+ const iterator = iteratorFn.call(node);
+
+ if (iterator) {
+ // We need to know how many total children are in this set, so that we
+ // can allocate enough id slots to acommodate them. So we must exhaust
+ // the iterator before we start recursively rendering the children.
+ // TODO: This is not great but I think it's inherent to the id
+ // generation algorithm.
+ let step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that.
+
+ if (!step.done) {
+ const children = [];
+
+ do {
+ children.push(step.value);
+ step = iterator.next();
+ } while (!step.done);
+
+ renderChildrenArray(request, task, children, childIndex);
+ return;
+ }
+
+ return;
+ }
+ } // Usables are a valid React node type. When React encounters a Usable in
+ // a child position, it unwraps it using the same algorithm as `use`. For
+ // example, for promises, React will throw an exception to unwind the
+ // stack, then replay the component once the promise resolves.
+ //
+ // A difference from `use` is that React will keep unwrapping the value
+ // until it reaches a non-Usable type.
+ //
+ // e.g. Usable>> should resolve to T
+
+
+ const maybeUsable = node;
+
+ if (typeof maybeUsable.then === 'function') {
+ const thenable = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable), childIndex);
+ }
+
+ if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, readContext$1(context), childIndex);
+ } // $FlowFixMe[method-unbinding]
+
+
+ const childString = Object.prototype.toString.call(node);
+ throw Error(formatProdErrorMessage(31, childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString));
+ }
+
+ if (typeof node === 'string') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+
+ if (typeof node === 'number') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, '' + node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+}
+
+function replayFragment(request, task, children, childIndex) {
+ // If we're supposed follow this array, we'd expect to see a ReplayNode matching
+ // this fragment.
+ const replay = task.replay;
+ const replayNodes = replay.nodes;
+
+ for (let j = 0; j < replayNodes.length; j++) {
+ const node = replayNodes[j];
+
+ if (node[1] !== childIndex) {
+ continue;
+ } // Matched a replayable path.
+
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderChildrenArray(request, task, children, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+ // This is an error, stash the component stack if it is null.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay; // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ replayNodes.splice(j, 1);
+ break;
+ }
+}
+
+function renderChildrenArray(request, task, children, childIndex) {
+ const prevKeyPath = task.keyPath;
+
+ if (childIndex !== -1) {
+ task.keyPath = [task.keyPath, 'Fragment', childIndex];
+
+ if (task.replay !== null) {
+ replayFragment(request, // $FlowFixMe: Refined.
+ task, children, childIndex);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ const prevTreeContext = task.treeContext;
+ const totalChildren = children.length;
+
+ if (task.replay !== null) {
+ // Replay
+ // First we need to check if we have any resume slots at this level.
+ const resumeSlots = task.replay.slots;
+
+ if (resumeSlots !== null && typeof resumeSlots === 'object') {
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ const resumeSegmentID = resumeSlots[i]; // TODO: If this errors we should still continue with the next sibling.
+
+ if (typeof resumeSegmentID === 'number') {
+ resumeNode(request, task, resumeSegmentID, node, i); // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ delete resumeSlots[i];
+ } else {
+ renderNode(request, task, node, i);
+ }
+ }
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ renderNode(request, task, node, i);
+ } // Because this context is always set right before rendering every child, we
+ // only need to reset it to the previous value at the very end.
+
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+}
+
+function spawnNewSuspendedReplayTask(request, task, thenableState, x) {
+ const newTask = createReplayTask(request, thenableState, task.replay, task.node, task.childIndex, task.blockedBoundary, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+}
+
+function spawnNewSuspendedRenderTask(request, task, thenableState, x) {
+ // Something suspended, we'll need to create a new segment and resolve it later.
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ const newTask = createRenderTask(request, thenableState, task.node, task.childIndex, task.blockedBoundary, newSegment, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+} // This is a non-destructive form of rendering a node. If it suspends it spawns
+// a new task and restores the context of this task to what it was before.
+
+
+function renderNode(request, task, node, childIndex) {
+ // Snapshot the current context in case something throws to interrupt the
+ // process.
+ const previousFormatContext = task.formatContext;
+ const previousLegacyContext = task.legacyContext;
+ const previousContext = task.context;
+ const previousKeyPath = task.keyPath;
+ const previousTreeContext = task.treeContext;
+
+ let x; // Store how much we've pushed at this point so we can reset it in case something
+ // suspended partially through writing something.
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState();
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedReplayTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode.
+
+ }
+ } else {
+ // Render
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedRenderTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ }
+ }
+ } // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ // Let's terminate the rest of the tree and don't render any siblings.
+
+
+ throw x;
+}
+
+function erroredReplay(request, boundary, error, replayNodes, resumeSlots) {
+ // Erroring during a replay doesn't actually cause an error by itself because
+ // that component has already rendered. What causes the error is the resumable
+ // points that we did not yet finish which will be below the point of the reset.
+ // For example, if we're replaying a path to a Suspense boundary that is not done
+ // that doesn't error the parent Suspense boundary.
+ // This might be a bit strange that the error in a parent gets thrown at a child.
+ // We log it only once and reuse the digest.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ abortRemainingReplayNodes(request, boundary, replayNodes, resumeSlots, error, errorDigest);
+}
+
+function erroredTask(request, boundary, error) {
+ // Report the error to a global handler.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ if (boundary === null) {
+ fatalError(request, error);
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+ // so we can flush it, if the parent already flushed.
+
+
+ if (boundary.parentFlushed) {
+ // We don't have a preference where in the queue this goes since it's likely
+ // to error on the client anyway. However, intentionally client-rendered
+ // boundaries should be flushed earlier so that they can start on the client.
+ // We reuse the same queue for errors.
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function abortTaskSoft(task) {
+ // This aborts task without aborting the parent boundary that it blocks.
+ // It's used for when we didn't need this task to complete the tree.
+ // If task was needed, then it should use abortTask instead.
+ const request = this;
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ finishedTask(request, boundary, segment);
+ }
+}
+
+function abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest) {
+ const resumedBoundary = createSuspenseBoundary(request, new Set());
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = rootSegmentID;
+ resumedBoundary.status = CLIENT_RENDERED;
+ resumedBoundary.errorDigest = errorDigest;
+
+ if (resumedBoundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(resumedBoundary);
+ }
+}
+
+function abortRemainingReplayNodes(request, boundary, nodes, slots, error, errorDigest) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+
+ if (node.length === 4) {
+ abortRemainingReplayNodes(request, boundary, node[2], node[3], error, errorDigest);
+ } else {
+ const boundaryNode = node;
+ const rootSegmentID = boundaryNode[5];
+ abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest);
+ }
+ } // Empty the set, since we've cleared it now.
+
+
+ nodes.length = 0;
+
+ if (slots !== null) {
+ // We had something still to resume in the parent boundary. We must trigger
+ // the error on the parent boundary since it's not able to complete.
+ if (boundary === null) {
+ throw Error(formatProdErrorMessage(487));
+ } else if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // Empty the set
+
+
+ if (typeof slots === 'object') {
+ for (const index in slots) {
+ delete slots[index];
+ }
+ }
+ }
+}
+
+function abortTask(task, request, error) {
+ // This aborts the task and aborts the parent that it blocks, putting it into
+ // client rendered mode.
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ }
+
+ if (boundary === null) {
+ if (request.status !== CLOSING && request.status !== CLOSED) {
+ const replay = task.replay;
+
+ if (replay === null) {
+ // We didn't complete the root so we have nothing to show. We can close
+ // the request;
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ return;
+ } else {
+ // If the shell aborts during a replay, that's not a fatal error. Instead
+ // we should be able to recover by client rendering all the root boundaries in
+ // the ReplaySet.
+ replay.pendingTasks--;
+
+ if (replay.pendingTasks === 0 && replay.nodes.length > 0) {
+ const errorDigest = logRecoverableError(request, error);
+ abortRemainingReplayNodes(request, null, replay.nodes, replay.slots, error, errorDigest);
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ }
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = logRecoverableError(request, error);
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // If this boundary was still pending then we haven't already cancelled its fallbacks.
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
+
+
+ boundary.fallbackAbortableTasks.forEach(fallbackTask => abortTask(fallbackTask, request, error));
+ boundary.fallbackAbortableTasks.clear();
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeShell(request) {
+ if (request.trackedPostpones === null) {
+ // We only emit early preloads on shell completion for renders. For prerenders
+ // we wait for the entire Request to finish because we are not responding to a
+ // live request and can wait for as much data as possible.
+ // we should only be calling completeShell when the shell is complete so we
+ // just use a literal here
+ const shellComplete = true;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ } // We have completed the shell so the shell can't error anymore.
+
+
+ request.onShellError = noop;
+ const onShellReady = request.onShellReady;
+ onShellReady();
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeAll(request) {
+ // During a render the shell must be complete if the entire request is finished
+ // however during a Prerender it is possible that the shell is incomplete because
+ // it postponed. We cannot use rootPendingTasks in the prerender case because
+ // those hit zero even when the shell postpones. Instead we look at the completedRootSegment
+ const shellComplete = request.trackedPostpones === null ? // Render, we assume it is completed
+ true : // Prerender Request, we use the state of the root segment
+ request.completedRootSegment === null || request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ const onAllReady = request.onAllReady;
+ onAllReady();
+}
+
+function queueCompletedSegment(boundary, segment) {
+ if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) {
+ // This is an empty segment. There's nothing to write, so we can instead transfer the ID
+ // to the child. That way any existing references point to the child.
+ const childSegment = segment.children[0];
+ childSegment.id = segment.id;
+ childSegment.parentFlushed = true;
+
+ if (childSegment.status === COMPLETED) {
+ queueCompletedSegment(boundary, childSegment);
+ }
+ } else {
+ const completedSegments = boundary.completedSegments;
+ completedSegments.push(segment);
+ }
+}
+
+function finishedTask(request, boundary, segment) {
+ if (boundary === null) {
+ if (segment !== null && segment.parentFlushed) {
+ if (request.completedRootSegment !== null) {
+ throw Error(formatProdErrorMessage(389));
+ }
+
+ request.completedRootSegment = segment;
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status === CLIENT_RENDERED) ; else if (boundary.pendingTasks === 0) {
+ if (boundary.status === PENDING) {
+ boundary.status = COMPLETED;
+ } // This must have been the last segment we were waiting on. This boundary is now complete.
+
+
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent segment already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ }
+ }
+
+ if (boundary.parentFlushed) {
+ // The segment might be part of a segment that didn't flush yet, but if the boundary's
+ // parent flushed, we need to schedule the boundary to be emitted.
+ request.completedBoundaries.push(boundary);
+ } // We can now cancel any pending task on the fallback since we won't need to show it anymore.
+ // This needs to happen after we read the parentFlushed flags because aborting can finish
+ // work which can trigger user code, which can start flushing, which can change those flags.
+ // If the boundary was POSTPONED, we still need to finish the fallback first.
+
+
+ if (boundary.status === COMPLETED) {
+ boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
+ boundary.fallbackAbortableTasks.clear();
+ }
+ } else {
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length === 1) {
+ // This is the first time since we last flushed that we completed anything.
+ // We can schedule this boundary to emit its partially completed segments early
+ // in case the parent has already been flushed.
+ if (boundary.parentFlushed) {
+ request.partialBoundaries.push(boundary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function retryTask(request, task) {
+ {
+ const blockedBoundary = task.blockedBoundary;
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, blockedBoundary ? blockedBoundary.resources : null);
+ }
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ retryReplayTask(request, // $FlowFixMe: Refined.
+ task);
+ } else {
+ retryRenderTask(request, // $FlowFixMe: Refined.
+ task, segment);
+ }
+}
+
+function retryRenderTask(request, task, segment) {
+ if (segment.status !== PENDING) {
+ // We completed this by other means before we had a chance to retry it.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+ pushSegmentFinale(segment.chunks, request.renderState, segment.lastPushedText, segment.textEmbedded);
+ task.abortSet.delete(task);
+ segment.status = COMPLETED;
+ finishedTask(request, task.blockedBoundary, segment);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.abortSet.delete(task);
+ segment.status = ERRORED;
+ erroredTask(request, task.blockedBoundary, x);
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function retryReplayTask(request, task) {
+ if (task.replay.pendingTasks === 0) {
+ // There are no pending tasks working on this set, so we must have aborted.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw Error(formatProdErrorMessage(488));
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ finishedTask(request, task.blockedBoundary, null);
+ } catch (thrownValue) {
+ resetHooksState();
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ erroredReplay(request, task.blockedBoundary, x, task.replay.nodes, task.replay.slots);
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function performWork(request) {
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ const prevContext = getActiveContext();
+ const prevDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = HooksDispatcher;
+ let prevCacheDispatcher;
+
+ {
+ prevCacheDispatcher = ReactCurrentCache.current;
+ ReactCurrentCache.current = DefaultCacheDispatcher;
+ }
+
+ const prevRequest = currentRequest;
+ currentRequest = request;
+
+ const prevResumableState = currentResumableState;
+ setCurrentResumableState(request.resumableState);
+
+ try {
+ const pingedTasks = request.pingedTasks;
+ let i;
+
+ for (i = 0; i < pingedTasks.length; i++) {
+ const task = pingedTasks[i];
+ retryTask(request, task);
+ }
+
+ pingedTasks.splice(0, i);
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ } finally {
+ setCurrentResumableState(prevResumableState);
+ ReactCurrentDispatcher.current = prevDispatcher;
+
+ {
+ ReactCurrentCache.current = prevCacheDispatcher;
+ }
+
+ if (prevDispatcher === HooksDispatcher) {
+ // This means that we were in a reentrant work loop. This could happen
+ // in a renderer that supports synchronous work like renderToString,
+ // when it's called from within another renderer.
+ // Normally we don't bother switching the contexts to their root/default
+ // values when leaving because we'll likely need the same or similar
+ // context again. However, when we're inside a synchronous loop like this
+ // we'll to restore the context to what it was before returning.
+ switchContext(prevContext);
+ }
+
+ currentRequest = prevRequest;
+ }
+}
+
+function flushSubtree(request, destination, segment) {
+ segment.parentFlushed = true;
+
+ switch (segment.status) {
+ case PENDING:
+ {
+ // We're emitting a placeholder for this segment to be filled in later.
+ // Therefore we'll need to assign it an ID - to refer to it by.
+ segment.id = request.nextSegmentId++; // Fallthrough
+ }
+
+ case POSTPONED:
+ {
+ const segmentID = segment.id; // When this segment finally completes it won't be embedded in text since it will flush separately
+
+ segment.lastPushedText = false;
+ segment.textEmbedded = false;
+ return writePlaceholder(destination, request.renderState, segmentID);
+ }
+
+ case COMPLETED:
+ {
+ segment.status = FLUSHED;
+ let r = true;
+ const chunks = segment.chunks;
+ let chunkIdx = 0;
+ const children = segment.children;
+
+ for (let childIdx = 0; childIdx < children.length; childIdx++) {
+ const nextChild = children[childIdx]; // Write all the chunks up until the next child.
+
+ for (; chunkIdx < nextChild.index; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ r = flushSegment(request, destination, nextChild);
+ } // Finally just write all the remaining chunks
+
+
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ if (chunkIdx < chunks.length) {
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
+ }
+
+ return r;
+ }
+
+ default:
+ {
+ throw Error(formatProdErrorMessage(390));
+ }
+ }
+}
+
+function flushSegment(request, destination, segment) {
+ const boundary = segment.boundary;
+
+ if (boundary === null) {
+ // Not a suspense boundary.
+ return flushSubtree(request, destination, segment);
+ }
+
+ boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to
+ // emit the content or the fallback now.
+
+ if (boundary.status === CLIENT_RENDERED) {
+ // Emit a client rendered suspense boundary wrapper.
+ // We never queue the inner boundary so we'll never emit its content or partial segments.
+ writeStartClientRenderedSuspenseBoundary(destination, request.renderState, boundary.errorDigest); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndClientRenderedSuspenseBoundary(destination);
+ } else if (boundary.status !== COMPLETED) {
+ if (boundary.status === PENDING) {
+ // For pending boundaries we lazily assign an ID to the boundary
+ // and root segment.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ }
+
+ if (boundary.completedSegments.length > 0) {
+ // If this is at least partially complete, we can queue it to be partially emitted early.
+ request.partialBoundaries.push(boundary);
+ } // This boundary is still loading. Emit a pending suspense boundary wrapper.
+
+
+ const id = boundary.rootSegmentID;
+ writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else if (boundary.byteSize > request.progressiveChunkSize) {
+ // This boundary is large and will be emitted separately so that we can progressively show
+ // other content. We add it to the queue during the flush because we have to ensure that
+ // the parent flushes first so that there's something to inject it into.
+ // We also have to make sure that it's emitted into the queue in a deterministic slot.
+ // I.e. we can't insert it here when it completes.
+ // Assign an ID to refer to the future content by.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper.
+
+ writeStartPendingSuspenseBoundary(destination, request.renderState, boundary.rootSegmentID); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else {
+ {
+ hoistResources(request.renderState, boundary.resources);
+ } // We can inline this boundary's content as a complete boundary.
+
+
+ writeStartCompletedSuspenseBoundary(destination);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length !== 1) {
+ throw Error(formatProdErrorMessage(391));
+ }
+
+ const contentSegment = completedSegments[0];
+ flushSegment(request, destination, contentSegment);
+ return writeEndCompletedSuspenseBoundary(destination);
+ }
+}
+
+function flushClientRenderedBoundary(request, destination, boundary) {
+ return writeClientRenderBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack);
+}
+
+function flushSegmentContainer(request, destination, segment) {
+ writeStartSegment(destination, request.renderState, segment.parentFormatContext, segment.id);
+ flushSegment(request, destination, segment);
+ return writeEndSegment(destination, segment.parentFormatContext);
+}
+
+function flushCompletedBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+ flushPartiallyCompletedSegment(request, destination, boundary, segment);
+ }
+
+ completedSegments.length = 0;
+
+ {
+ writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+
+ return writeCompletedBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.resources);
+}
+
+function flushPartialBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+
+ if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) {
+ i++;
+ completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority
+ // might want to write later.
+
+ return false;
+ }
+ }
+
+ completedSegments.splice(0, i);
+
+ {
+ // The way this is structured we only write resources for partial boundaries
+ // if there is no backpressure. Later before we complete the boundary we
+ // will write resources regardless of backpressure before we emit the
+ // completion instruction
+ return writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+}
+
+function flushPartiallyCompletedSegment(request, destination, boundary, segment) {
+ if (segment.status === FLUSHED) {
+ // We've already flushed this inline.
+ return true;
+ }
+
+ const segmentID = segment.id;
+
+ if (segmentID === -1) {
+ // This segment wasn't previously referred to. This happens at the root of
+ // a boundary. We make kind of a leap here and assume this is the root.
+ const rootSegmentID = segment.id = boundary.rootSegmentID;
+
+ if (rootSegmentID === -1) {
+ throw Error(formatProdErrorMessage(392));
+ }
+
+ return flushSegmentContainer(request, destination, segment);
+ } else if (segmentID === boundary.rootSegmentID) {
+ // When we emit postponed boundaries, we might have assigned the ID already
+ // but it's still the root segment so we can't inject it into the parent yet.
+ return flushSegmentContainer(request, destination, segment);
+ } else {
+ flushSegmentContainer(request, destination, segment);
+ return writeCompletedSegmentInstruction(destination, request.resumableState, request.renderState, segmentID);
+ }
+}
+
+function flushCompletedQueues(request, destination) {
+ beginWriting();
+
+ try {
+ // The structure of this is to go through each queue one by one and write
+ // until the sink tells us to stop. When we should stop, we still finish writing
+ // that item fully and then yield. At that point we remove the already completed
+ // items up until the point we completed them.
+ let i;
+ const completedRootSegment = request.completedRootSegment;
+
+ if (completedRootSegment !== null) {
+ if (completedRootSegment.status === POSTPONED) {
+ // We postponed the root, so we write nothing.
+ return;
+ } else if (request.pendingRootTasks === 0) {
+ if (enableFloat) {
+ writePreamble(destination, request.resumableState, request.renderState, request.allPendingTasks === 0 && request.trackedPostpones === null);
+ }
+
+ flushSegment(request, destination, completedRootSegment);
+ request.completedRootSegment = null;
+ writeCompletedRoot(destination, request.renderState, request.resumableState);
+ } else {
+ // We haven't flushed the root yet so we don't need to check any other branches further down
+ return;
+ }
+ }
+
+ if (enableFloat) {
+ writeHoistables(destination, request.resumableState, request.renderState);
+ } // We emit client rendering instructions for already emitted boundaries first.
+ // This is so that we can signal to the client to start client rendering them as
+ // soon as possible.
+
+
+ const clientRenderedBoundaries = request.clientRenderedBoundaries;
+
+ for (i = 0; i < clientRenderedBoundaries.length; i++) {
+ const boundary = clientRenderedBoundaries[i];
+
+ if (!flushClientRenderedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ clientRenderedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries
+ // that are completely done since we can actually show them, than it is to emit
+ // any individual segments from a partially complete boundary.
+
+ const completedBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < completedBoundaries.length; i++) {
+ const boundary = completedBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ completedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before
+ // we continue with lower priorities.
+
+ completeWriting(destination);
+ beginWriting(destination); // TODO: Here we'll emit data used by hydration.
+ // Next we emit any segments of any boundaries that are partially complete
+ // but not deeply complete.
+
+ const partialBoundaries = request.partialBoundaries;
+
+ for (i = 0; i < partialBoundaries.length; i++) {
+ const boundary = partialBoundaries[i];
+
+ if (!flushPartialBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ partialBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had
+ // boundaries added to it in case they were too larged to be inlined.
+ // New ones might be added in this loop.
+
+ const largeBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < largeBoundaries.length; i++) {
+ const boundary = largeBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ largeBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ largeBoundaries.splice(0, i);
+ } finally {
+ if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because
+ // either they have pending task or they're complete.
+ ) {
+ request.flushScheduled = false;
+
+ {
+ // We write the trailing tags but only if don't have any data to resume.
+ // If we need to resume we'll write the postamble in the resume instead.
+ {
+ writePostamble(destination, request.resumableState);
+ }
+ }
+
+ completeWriting(destination);
+
+
+ close(destination); // We need to stop flowing now because we do not want any async contexts which might call
+ // float methods to initiate any flushes after this point
+
+ stopFlowing(request);
+ } else {
+ completeWriting(destination);
+ }
+ }
+}
+
+function startWork(request) {
+ request.flushScheduled = request.destination !== null;
+
+ {
+ scheduleWork(() => performWork(request));
+ }
+
+ if (request.trackedPostpones === null) {
+ // this is either a regular render or a resume. For regular render we want
+ // to call emitEarlyPreloads after the first performWork because we want
+ // are responding to a live request and need to balance sending something early
+ // (i.e. don't want for the shell to finish) but we need something to send.
+ // The only implementation of this is for DOM at the moment and during resumes nothing
+ // actually emits but the code paths here are the same.
+ // During a prerender we don't want to be too aggressive in emitting early preloads
+ // because we aren't responding to a live request and we can wait for the prerender to
+ // postpone before we emit anything.
+ {
+ scheduleWork(() => enqueueEarlyPreloadsAfterInitialWork(request));
+ }
+ }
+}
+
+function enqueueEarlyPreloadsAfterInitialWork(request) {
+ const shellComplete = request.pendingRootTasks === 0;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+
+function enqueueFlush(request) {
+ if (request.flushScheduled === false && // If there are pinged tasks we are going to flush anyway after work completes
+ request.pingedTasks.length === 0 && // If there is no destination there is nothing we can flush to. A flush will
+ // happen when we start flowing again
+ request.destination !== null) {
+ request.flushScheduled = true;
+ scheduleWork(() => {
+ // We need to existence check destination again here because it might go away
+ // in between the enqueueFlush call and the work execution
+ const destination = request.destination;
+
+ if (destination) {
+ flushCompletedQueues(request, destination);
+ } else {
+ request.flushScheduled = false;
+ }
+ });
+ }
+} // This function is intented to only be called during the pipe function for the Node builds.
+function startFlowing(request, destination) {
+ if (request.status === CLOSING) {
+ request.status = CLOSED;
+ closeWithError(destination, request.fatalError);
+ return;
+ }
+
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ if (request.destination !== null) {
+ // We're already flowing.
+ return;
+ }
+
+ request.destination = destination;
+
+ try {
+ flushCompletedQueues(request, destination);
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function stopFlowing(request) {
+ request.destination = null;
+} // This is called to early terminate a request. It puts all pending boundaries in client rendered state.
+
+function abort(request, reason) {
+ try {
+ const abortableTasks = request.abortableTasks;
+
+ if (abortableTasks.size > 0) {
+ const error = reason === undefined ? Error(formatProdErrorMessage(432)) : reason;
+ abortableTasks.forEach(task => abortTask(task, request, error));
+ abortableTasks.clear();
+ }
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function flushResources(request) {
+ enqueueFlush(request);
+}
+function getFormState(request) {
+ return request.formState;
+}
+function getResumableState(request) {
+ return request.resumableState;
+}
+function getRenderState(request) {
+ return request.renderState;
+}
+
+function renderToReadableStream(children, options) {
+ return new Promise((resolve, reject) => {
+ let onFatalError;
+ let onAllReady;
+ const allReady = new Promise((res, rej) => {
+ onAllReady = res;
+ onFatalError = rej;
+ });
+
+ function onShellReady() {
+ const stream = new ReadableStream({
+ type: 'bytes',
+ pull: controller => {
+ startFlowing(request, controller);
+ },
+ cancel: reason => {
+ stopFlowing(request);
+ abort(request, reason);
+ }
+ }, // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
+ {
+ highWaterMark: 0
+ }); // TODO: Move to sub-classing ReadableStream.
+
+ stream.allReady = allReady;
+ resolve(stream);
+ }
+
+ function onShellError(error) {
+ // If the shell errors the caller of `renderToReadableStream` won't have access to `allReady`.
+ // However, `allReady` will be rejected by `onFatalError` as well.
+ // So we need to catch the duplicate, uncatchable fatal error in `allReady` to prevent a `UnhandledPromiseRejection`.
+ allReady.catch(() => {});
+ reject(error);
+ }
+
+ const onHeaders = options ? options.onHeaders : undefined;
+ let onHeadersImpl;
+
+ if (onHeaders) {
+ onHeadersImpl = headersDescriptor => {
+ onHeaders(new Headers(headersDescriptor));
+ };
+ }
+
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ const request = createRequest(children, resumableState, createRenderState(resumableState, options ? options.nonce : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, onHeadersImpl, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, onAllReady, onShellReady, onShellError, onFatalError, options ? options.onPostpone : undefined, options ? options.formState : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+exports.renderToReadableStream = renderToReadableStream;
+exports.version = ReactVersion;
\ No newline at end of file
diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.production.min.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.production.min.js
index c444836796320..4bd43716a27fd 100644
--- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.production.min.js
+++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.production.min.js
@@ -1,13 +1,11 @@
-/**
- * @license React
- * react-dom-server.browser.production.min.js
- *
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
/*
+ React
+ react-dom-server.browser.production.min.js
+
+ Copyright (c) Meta Platforms, Inc. and affiliates.
+
+ This source code is licensed under the MIT license found in the
+ LICENSE file in the root directory of this source tree.
JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
@@ -33,8 +31,8 @@
*/
'use strict';var aa=require("next/dist/compiled/react"),ba=require("react-dom");function k(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;c>>16)&65535)<<16)&4294967295;f=f<<15|f>>>17;f=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295;e^=f;e=e<<13|e>>>19;e=5*(e&65535)+((5*(e>>>16)&65535)<<16)&4294967295;e=(e&65535)+27492+(((e>>>16)+58964&65535)<<16)}f=0;switch(c){case 3:f^=(a.charCodeAt(b+2)&255)<<
-16;case 2:f^=(a.charCodeAt(b+1)&255)<<8;case 1:f^=a.charCodeAt(b)&255,f=3432918353*(f&65535)+((3432918353*(f>>>16)&65535)<<16)&4294967295,f=f<<15|f>>>17,e^=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295}e^=a.length;e^=e>>>16;e=2246822507*(e&65535)+((2246822507*(e>>>16)&65535)<<16)&4294967295;e^=e>>>13;e=3266489909*(e&65535)+((3266489909*(e>>>16)&65535)<<16)&4294967295;return(e^e>>>16)>>>0}var m=null,r=0;
-function v(a,b){if(0!==b.byteLength)if(512>>16)&65535)<<16)&4294967295,f=f<<15|f>>>17,e^=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295}e^=a.length;e^=e>>>16;e=2246822507*(e&65535)+((2246822507*(e>>>16)&65535)<<16)&4294967295;e^=e>>>13;e=3266489909*(e&65535)+((3266489909*(e>>>16)&65535)<<16)&4294967295;return(e^e>>>16)>>>0}var m=null,q=0;
+function v(a,b){if(0!==b.byteLength)if(512 '),ob=y("');
+const startScriptSrc = stringToPrecomputedChunk('');
+/**
+ * This escaping function is designed to work with bootstrapScriptContent and importMap only.
+ * because we know we are escaping the entire script. We can avoid for instance
+ * escaping html comment string sequences that are valid javascript as well because
+ * if there are no sebsequent '); // Since we store headers as strings we deal with their length in utf16 code units
+// rather than visual characters or the utf8 encoding that is used for most binary
+// serialization. Some common HTTP servers only allow for headers to be 4kB in length.
+// We choose a default length that is likely to be well under this already limited length however
+// pathological cases may still cause the utf-8 encoding of the headers to approach this limit.
+// It should also be noted that this maximum is a soft maximum. we have not reached the limit we will
+// allow one more header to be captured which means in practice if the limit is approached it will be exceeded
+
+const DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep track of what we've already written so we can refer back to it.
+// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
+// is set, the server will send instructions via data attributes (instead of inline scripts)
+
+function createRenderState(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+ const inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const completeSegmentData1 = stringToPrecomputedChunk('');
+const completeBoundaryData1 = stringToPrecomputedChunk('');
+const clientRenderData1 = stringToPrecomputedChunk('
+ return writeChunkAndReturn(destination, clientRenderDataEnd);
+ }
+}
+const regexForJSStringsInInstructionScripts = /[<\u2028\u2029]/g;
+
+function escapeJSStringsForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInInstructionScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const regexForJSStringsInScripts = /[&><\u2028\u2029]/g;
+
+function escapeJSObjectForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '&':
+ return '\\u0026';
+
+ case '>':
+ return '\\u003e';
+
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(''); // Tracks whether the boundary currently flushing is flushign style tags or has any
+// stylesheet dependencies not flushed in the Preamble.
+
+let currentlyRenderingBoundaryHasStylesToHoist = false; // Acts as a return value for the forEach execution of style tag flushing.
+
+let destinationHasCapacity = true;
+
+function flushStyleTagsLateForBoundary(styleQueue) {
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs;
+
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, lateStyleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ writeChunk(this, lateStyleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, lateStyleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ destinationHasCapacity = writeChunkAndReturn(this, lateStyleTagTemplateClose); // We wrote style tags for this boundary and we may need to emit a script
+ // to hoist them.
+
+ currentlyRenderingBoundaryHasStylesToHoist = true; // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function hasStylesToHoist(stylesheet) {
+ // We need to reveal boundaries with styles whenever a stylesheet it depends on is either
+ // not flushed or flushed after the preamble (shell).
+ if (stylesheet.state !== PREAMBLE) {
+ currentlyRenderingBoundaryHasStylesToHoist = true;
+ return true;
+ }
+
+ return false;
+}
+
+function writeResourcesForBoundary(destination, boundaryResources, renderState) {
+ // Reset these on each invocation, they are only safe to read in this function
+ currentlyRenderingBoundaryHasStylesToHoist = false;
+ destinationHasCapacity = true; // Flush style tags for each precedence this boundary depends on
+
+ boundaryResources.styles.forEach(flushStyleTagsLateForBoundary, destination); // Determine if this boundary has stylesheets that need to be awaited upon completion
+
+ boundaryResources.stylesheets.forEach(hasStylesToHoist);
+
+ if (currentlyRenderingBoundaryHasStylesToHoist) {
+ renderState.stylesToHoist = true;
+ }
+
+ return destinationHasCapacity;
+}
+
+function flushResource(resource) {
+ for (let i = 0; i < resource.length; i++) {
+ writeChunk(this, resource[i]);
+ }
+
+ resource.length = 0;
+}
+
+const stylesheetFlushingQueue = [];
+
+function flushStyleInPreamble(stylesheet, key, map) {
+ // We still need to encode stylesheet chunks
+ // because unlike most Hoistables and Resources we do not eagerly encode
+ // them during render. This is because if we flush late we have to send a
+ // different encoding and we don't want to encode multiple times
+ pushLinkImpl(stylesheetFlushingQueue, stylesheet.props);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ stylesheet.state = PREAMBLE;
+}
+
+const styleTagResourceOpen1 = stringToPrecomputedChunk('');
+
+function flushStylesInPreamble(styleQueue, precedence) {
+ const hasStylesheets = styleQueue.sheets.size > 0;
+ styleQueue.sheets.forEach(flushStyleInPreamble, this);
+ styleQueue.sheets.clear();
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs; // If we don't emit any stylesheets at this precedence we still need to maintain the precedence
+ // order so even if there are no rules for style tags at this precedence we emit an empty style
+ // tag with the data-precedence attribute
+
+ if (!hasStylesheets || hrefs.length) {
+ writeChunk(this, styleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, styleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ }
+
+ writeChunk(this, styleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ writeChunk(this, styleTagResourceClose); // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function preloadLateStyle(stylesheet) {
+ if (stylesheet.state === PENDING$1) {
+ stylesheet.state = PRELOADED;
+ const preloadProps = preloadAsStylePropsFromProps(stylesheet.props.href, stylesheet.props);
+ pushLinkImpl(stylesheetFlushingQueue, preloadProps);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ }
+}
+
+function preloadLateStyles(styleQueue) {
+ styleQueue.sheets.forEach(preloadLateStyle, this);
+ styleQueue.sheets.clear();
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+
+function writePreamble(destination, resumableState, renderState, willFlushAllSegments) {
+ // This function must be called exactly once on every request
+ if (!willFlushAllSegments && renderState.externalRuntimeScript) {
+ // If the root segment is incomplete due to suspended tasks
+ // (e.g. willFlushAllSegments = false) and we are using data
+ // streaming format, ensure the external runtime is sent.
+ // (User code could choose to send this even earlier by calling
+ // preinit(...), if they know they will suspend).
+ const _renderState$external = renderState.externalRuntimeScript,
+ src = _renderState$external.src,
+ chunks = _renderState$external.chunks;
+ internalPreinitScript(resumableState, renderState, src, chunks);
+ }
+
+ const htmlChunks = renderState.htmlChunks;
+ const headChunks = renderState.headChunks;
+ let i = 0; // Emit open tags before Hoistables and Resources
+
+ if (htmlChunks) {
+ // We have an to emit as part of the preamble
+ for (i = 0; i < htmlChunks.length; i++) {
+ writeChunk(destination, htmlChunks[i]);
+ }
+
+ if (headChunks) {
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } else {
+ // We did not render a head but we emitted an so we emit one now
+ writeChunk(destination, startChunkForTag('head'));
+ writeChunk(destination, endOfStartTag);
+ }
+ } else if (headChunks) {
+ // We do not have an but we do have a
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } // Emit high priority Hoistables
+
+
+ const charsetChunks = renderState.charsetChunks;
+
+ for (i = 0; i < charsetChunks.length; i++) {
+ writeChunk(destination, charsetChunks[i]);
+ }
+
+ charsetChunks.length = 0; // emit preconnect resources
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Flush unblocked stylesheets by precedence
+
+ renderState.styles.forEach(flushStylesInPreamble, destination);
+ const importMapChunks = renderState.importMapChunks;
+
+ for (i = 0; i < importMapChunks.length; i++) {
+ writeChunk(destination, importMapChunks[i]);
+ }
+
+ importMapChunks.length = 0;
+ renderState.bootstrapScripts.forEach(flushResource, destination);
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0; // Flush closing head if necessary
+
+ if (htmlChunks && headChunks === null) {
+ // We have an rendered but no rendered. We however inserted
+ // a up above so we need to emit the now. This is safe because
+ // if the main content contained the it would also have provided a
+ // . This means that all the content inside is either or
+ // invalid HTML
+ writeChunk(destination, endChunkForTag('head'));
+ }
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+function writeHoistables(destination, resumableState, renderState) {
+ let i = 0; // Emit high priority Hoistables
+ // We omit charsetChunks because we have already sent the shell and if it wasn't
+ // already sent it is too late now.
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Preload any stylesheets. these will emit in a render instruction that follows this
+ // but we want to kick off preloading as soon as possible
+
+ renderState.styles.forEach(preloadLateStyles, destination); // We only hoist importmaps that are configured through createResponse and that will
+ // always flush in the preamble. Generally we don't expect people to render them as
+ // tags when using React but if you do they are going to be treated like regular inline
+ // scripts and flush after other hoistables which is problematic
+ // bootstrap scripts should flush above script priority but these can only flush in the preamble
+ // so we elide the code here for performance
+
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0;
+}
+function writePostamble(destination, resumableState) {
+ if (resumableState.hasBody) {
+ writeChunk(destination, endChunkForTag('body'));
+ }
+
+ if (resumableState.hasHtml) {
+ writeChunk(destination, endChunkForTag('html'));
+ }
+}
+const arrayFirstOpenBracket = stringToPrecomputedChunk('[');
+const arraySubsequentOpenBracket = stringToPrecomputedChunk(',[');
+const arrayInterstitial = stringToPrecomputedChunk(',');
+const arrayCloseBracket = stringToPrecomputedChunk(']'); // This function writes a 2D array of strings to be embedded in javascript.
+// E.g.
+// [["JS_escaped_string1", "JS_escaped_string2"]]
+
+function writeStyleResourceDependenciesInJS(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInJS(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInJS(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInJS(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+}
+
+function writeStyleResourceDependencyInJS(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedPrecedence)));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInJS(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInJS(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeName)));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeValue)));
+} // This function writes a 2D array of strings to be embedded in an attribute
+// value and read with JSON.parse in ReactDOMServerExternalRuntime.js
+// E.g.
+// [["JSON_escaped_string1", "JSON_escaped_string2"]]
+
+
+function writeStyleResourceDependenciesInAttr(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInAttr(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInAttr(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInAttr(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+}
+
+function writeStyleResourceDependencyInAttr(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedPrecedence))));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInAttr(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInAttr(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeName))));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeValue))));
+}
+/**
+ * Resources
+ */
+
+
+const PENDING$1 = 0;
+const PRELOADED = 1;
+const PREAMBLE = 2;
+const LATE = 3;
+function createBoundaryResources() {
+ return {
+ styles: new Set(),
+ stylesheets: new Set()
+ };
+}
+function setCurrentlyRenderingBoundaryResourcesTarget(renderState, boundaryResources) {
+ renderState.boundaryResources = boundaryResources;
+}
+
+function getResourceKey(href) {
+ return href;
+}
+
+function getImageResourceKey(href, imageSrcSet, imageSizes) {
+ if (imageSrcSet) {
+ return imageSrcSet + '\n' + (imageSizes || '');
+ }
+
+ return href;
+}
+
+function prefetchDNS(href) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const key = getResourceKey(href);
+
+ if (!resumableState.dnsResources.hasOwnProperty(key)) {
+ resumableState.dnsResources[key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPrefetchDNSAsHeader(href), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this as resettable in case we are prerendering and postpone in the Shell
+ renderState.resets.dns[key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ // Encode as element
+ const resource = [];
+ pushLinkImpl(resource, {
+ href,
+ rel: 'dns-prefetch'
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preconnect(href, crossOrigin) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const bucket = crossOrigin === 'use-credentials' ? 'credentials' : typeof crossOrigin === 'string' ? 'anonymous' : 'default';
+ const key = getResourceKey(href);
+
+ if (!resumableState.connectResources[bucket].hasOwnProperty(key)) {
+ resumableState.connectResources[bucket][key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreconnectAsHeader(href, crossOrigin), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this in resettableState in case we are prerending and postpone in the Shell
+ renderState.resets.connect[bucket][key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ const resource = [];
+ pushLinkImpl(resource, {
+ rel: 'preconnect',
+ href,
+ crossOrigin
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preload(href, as, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (as && href) {
+ switch (as) {
+ case 'image':
+ {
+ let imageSrcSet, imageSizes, fetchPriority;
+
+ if (options) {
+ imageSrcSet = options.imageSrcSet;
+ imageSizes = options.imageSizes;
+ fetchPriority = options.fetchPriority;
+ }
+
+ const key = getImageResourceKey(href, imageSrcSet, imageSizes);
+
+ if (resumableState.imageResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resumableState.imageResources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && fetchPriority === 'high' && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit a preload as a header so we
+ // track this to make sure we don't reset it.
+ renderState.resets.image[key] = PRELOAD_NO_CREDS;
+
+ if (headers.highImagePreloads) {
+ headers.highImagePreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.highImagePreloads += header;
+ } else {
+ // If we don't have headers to write to we have to encode as elements to flush in the head
+ // When we have imageSrcSet the browser probably cannot load the right version from headers
+ // (this should be verified by testing). For now we assume these need to go in the head
+ // as elements even if headers are available.
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ // There is a bug in Safari where imageSrcSet is not respected on preload links
+ // so we omit the href here if we have imageSrcSet b/c safari will load the wrong image.
+ // This harms older browers that do not support imageSrcSet by making their preloads not work
+ // but this population is shrinking fast and is already small so we accept this tradeoff.
+ href: imageSrcSet ? undefined : href,
+ as
+ }, options));
+
+ if (fetchPriority === 'high') {
+ renderState.highImagePreloads.add(resource);
+ } else {
+ renderState.bulkPreloads.add(resource); // Stash the resource in case we need to promote it to higher priority
+ // when an img tag is rendered
+
+ renderState.preloads.images.set(key, resource);
+ }
+ }
+
+ break;
+ }
+
+ case 'style':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.styleResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.styleResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.stylesheets.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ break;
+ }
+
+ case 'script':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.scriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ renderState.preloads.scripts.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.scriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ break;
+ }
+
+ default:
+ {
+ const key = getResourceKey(href);
+ const hasAsType = resumableState.unknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.unknownResources[as] = resources;
+ }
+
+ resources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && as === 'font' && ( // We compute the header here because we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit this preload so we
+ // track it here to prevent it from being reset.
+ renderState.resets.font[key] = PRELOAD_NO_CREDS;
+
+ if (headers.fontPreloads) {
+ headers.fontPreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.fontPreloads += header;
+ } else {
+ // We either don't have headers or we are preloading something that does
+ // not warrant elevated priority so we encode as an element.
+ const resource = [];
+
+ const props = assign({
+ rel: 'preload',
+ href,
+ as
+ }, options);
+
+ pushLinkImpl(resource, props);
+
+ switch (as) {
+ case 'font':
+ renderState.fontPreloads.add(resource);
+ break;
+ // intentional fall through
+
+ default:
+ renderState.bulkPreloads.add(resource);
+ }
+ }
+ }
+ } // If we got this far we created a new resource
+
+
+ flushResources(request);
+ }
+}
+
+function preloadModule(href, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ const key = getResourceKey(href);
+ const as = options && typeof options.as === 'string' ? options.as : 'script';
+ let resource;
+
+ switch (as) {
+ case 'script':
+ {
+ if (resumableState.moduleScriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resource = [];
+ resumableState.moduleScriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.moduleScripts.set(key, resource);
+ break;
+ }
+
+ default:
+ {
+ const hasAsType = resumableState.moduleUnknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.moduleUnknownResources[as] = resources;
+ }
+
+ resource = [];
+ resources[key] = PRELOAD_NO_CREDS;
+ }
+ }
+
+ pushLinkImpl(resource, assign({
+ rel: 'modulepreload',
+ href
+ }, options));
+ renderState.bulkPreloads.add(resource); // If we got this far we created a new resource
+
+ flushResources(request);
+ }
+}
+
+function preinitStyle(href, precedence, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ precedence = precedence || 'default';
+ const key = getResourceKey(href);
+ let styleQueue = renderState.styles.get(precedence);
+ const hasKey = resumableState.styleResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.styleResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.styleResources[key] = EXISTS; // If this is the first time we've encountered this precedence we need
+ // to create a StyleQueue
+
+ if (!styleQueue) {
+ styleQueue = {
+ precedence: stringToChunk(escapeTextForBrowser(precedence)),
+ rules: [],
+ hrefs: [],
+ sheets: new Map()
+ };
+ renderState.styles.set(precedence, styleQueue);
+ }
+
+ const resource = {
+ state: PENDING$1,
+ props: assign({
+ rel: 'stylesheet',
+ href,
+ 'data-precedence': precedence
+ }, options)
+ };
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(resource.props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.stylesheets.get(key);
+
+ if (preloadResource && preloadResource.length > 0) {
+ // The Preload for this resource was created in this render pass and has not flushed yet so
+ // we need to clear it to avoid it flushing.
+ preloadResource.length = 0;
+ } else {
+ // Either the preload resource from this render already flushed in this render pass
+ // or the preload flushed in a prior pass (prerender). In either case we need to mark
+ // this resource as already having been preloaded.
+ resource.state = PRELOADED;
+ }
+ } // We add the newly created resource to our StyleQueue and if necessary
+ // track the resource with the currently rendering boundary
+
+
+ styleQueue.sheets.set(key, resource); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+ }
+}
+
+function preinitScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.scriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.scriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.scriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.scripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+}
+
+function preinitModuleScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.moduleScriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.moduleScriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.moduleScriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ type: 'module',
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.moduleScripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+} // This function is only safe to call at Request start time since it assumes
+// that each module has not already been preloaded. If we find a need to preload
+// scripts at any other point in time we will need to check whether the preload
+// already exists and not assume it
+
+
+function preloadBootstrapScriptOrModule(resumableState, renderState, href, props) {
+
+ const key = getResourceKey(href);
+ // used to preinit the resource. If a script can be preinited then it shouldn't
+ // be a bootstrap script/module and if it is a bootstrap script/module then it
+ // must not be safe to emit early. To avoid possibly allowing for preinits of
+ // bootstrap scripts/modules we occlude these keys.
+
+
+ resumableState.scriptResources[key] = EXISTS;
+ resumableState.moduleScriptResources[key] = EXISTS;
+ const resource = [];
+ pushLinkImpl(resource, props);
+ renderState.bootstrapScripts.add(resource);
+}
+
+function internalPreinitScript(resumableState, renderState, src, chunks) {
+ const key = getResourceKey(src);
+
+ if (!resumableState.scriptResources.hasOwnProperty(key)) {
+ const resource = chunks;
+ resumableState.scriptResources[key] = EXISTS;
+ renderState.scripts.add(resource);
+ }
+
+ return;
+}
+
+function preloadAsStylePropsFromProps(href, props) {
+ return {
+ rel: 'preload',
+ as: 'style',
+ href: href,
+ crossOrigin: props.crossOrigin,
+ fetchPriority: props.fetchPriority,
+ integrity: props.integrity,
+ media: props.media,
+ hrefLang: props.hrefLang,
+ referrerPolicy: props.referrerPolicy
+ };
+}
+
+function stylesheetPropsFromRawProps(rawProps) {
+ return assign({}, rawProps, {
+ 'data-precedence': rawProps.precedence,
+ precedence: null
+ });
+}
+
+function adoptPreloadCredentials(target, preloadState) {
+ if (target.crossOrigin == null) target.crossOrigin = preloadState[0];
+ if (target.integrity == null) target.integrity = preloadState[1];
+}
+
+function getPrefetchDNSAsHeader(href) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ return "<" + escapedHref + ">; rel=dns-prefetch";
+}
+
+function getPreconnectAsHeader(href, crossOrigin) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ let value = "<" + escapedHref + ">; rel=preconnect";
+
+ if (typeof crossOrigin === 'string') {
+ const escapedCrossOrigin = escapeStringForLinkHeaderQuotedParamValueContext(crossOrigin);
+ value += "; crossorigin=\"" + escapedCrossOrigin + "\"";
+ }
+
+ return value;
+}
+
+function getPreloadAsHeader(href, as, params) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ const escapedAs = escapeStringForLinkHeaderQuotedParamValueContext(as);
+ let value = "<" + escapedHref + ">; rel=preload; as=\"" + escapedAs + "\"";
+
+ for (const paramName in params) {
+ if (hasOwnProperty.call(params, paramName)) {
+ const paramValue = params[paramName];
+
+ if (typeof paramValue === 'string') {
+ value += "; " + paramName.toLowerCase() + "=\"" + escapeStringForLinkHeaderQuotedParamValueContext(paramValue) + "\"";
+ }
+ }
+ }
+
+ return value;
+}
+
+function getStylesheetPreloadAsHeader(stylesheet) {
+ const props = stylesheet.props;
+ const preloadOptions = {
+ crossOrigin: props.crossOrigin,
+ integrity: props.integrity,
+ nonce: props.nonce,
+ type: props.type,
+ fetchPriority: props.fetchPriority,
+ referrerPolicy: props.referrerPolicy,
+ media: props.media
+ };
+ return getPreloadAsHeader(props.href, 'style', preloadOptions);
+} // This escaping function is only safe to use for href values being written into
+// a "Link" header in between `<` and `>` characters. The primary concern with the href is
+// to escape the bounding characters as well as new lines. This is unsafe to use in any other
+// context
+
+
+const regexForHrefInLinkHeaderURLContext = /[<>\r\n]/g;
+
+function escapeHrefForLinkHeaderURLContext(hrefInput) {
+
+ const coercedHref = '' + hrefInput;
+ return coercedHref.replace(regexForHrefInLinkHeaderURLContext, escapeHrefForLinkHeaderURLContextReplacer);
+}
+
+function escapeHrefForLinkHeaderURLContextReplacer(match) {
+ switch (match) {
+ case '<':
+ return '%3C';
+
+ case '>':
+ return '%3E';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+} // This escaping function is only safe to use for quoted param values in an HTTP header.
+// It is unsafe to use for any value not inside quote marks in parater value position.
+
+
+const regexForLinkHeaderQuotedParamValueContext = /["';,\r\n]/g;
+
+function escapeStringForLinkHeaderQuotedParamValueContext(value, name) {
+
+ const coerced = '' + value;
+ return coerced.replace(regexForLinkHeaderQuotedParamValueContext, escapeStringForLinkHeaderQuotedParamValueContextReplacer);
+}
+
+function escapeStringForLinkHeaderQuotedParamValueContextReplacer(match) {
+ switch (match) {
+ case '"':
+ return '%22';
+
+ case "'":
+ return '%27';
+
+ case ';':
+ return '%3B';
+
+ case ',':
+ return '%2C';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+}
+
+function hoistStyleQueueDependency(styleQueue) {
+ this.styles.add(styleQueue);
+}
+
+function hoistStylesheetDependency(stylesheet) {
+ this.stylesheets.add(stylesheet);
+}
+
+function hoistResources(renderState, source) {
+ const currentBoundaryResources = renderState.boundaryResources;
+
+ if (currentBoundaryResources) {
+ source.styles.forEach(hoistStyleQueueDependency, currentBoundaryResources);
+ source.stylesheets.forEach(hoistStylesheetDependency, currentBoundaryResources);
+ }
+} // This function is called at various times depending on whether we are rendering
+// or prerendering. In this implementation we only actually emit headers once and
+// subsequent calls are ignored. We track whether the request has a completed shell
+// to determine whether we will follow headers with a flush including stylesheets.
+// In the context of prerrender we don't have a completed shell when the request finishes
+// with a postpone in the shell. In the context of a render we don't have a completed shell
+// if this is called before the shell finishes rendering which usually will happen anytime
+// anything suspends in the shell.
+
+function emitEarlyPreloads(renderState, resumableState, shellComplete) {
+ const onHeaders = renderState.onHeaders;
+
+ if (onHeaders) {
+ const headers = renderState.headers;
+
+ if (headers) {
+ let linkHeader = headers.preconnects;
+
+ if (headers.fontPreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.fontPreloads;
+ }
+
+ if (headers.highImagePreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.highImagePreloads;
+ }
+
+ if (!shellComplete) {
+ // We use raw iterators because we want to be able to halt iteration
+ // We could refactor renderState to store these dually in arrays to
+ // make this more efficient at the cost of additional memory and
+ // write overhead. However this code only runs once per request so
+ // for now I consider this sufficient.
+ const queueIter = renderState.styles.values();
+
+ outer: for (let queueStep = queueIter.next(); headers.remainingCapacity > 0 && !queueStep.done; queueStep = queueIter.next()) {
+ const sheets = queueStep.value.sheets;
+ const sheetIter = sheets.values();
+
+ for (let sheetStep = sheetIter.next(); headers.remainingCapacity > 0 && !sheetStep.done; sheetStep = sheetIter.next()) {
+ const sheet = sheetStep.value;
+ const props = sheet.props;
+ const key = getResourceKey(props.href);
+ const header = getStylesheetPreloadAsHeader(sheet); // We mutate the capacity b/c we don't want to keep checking if later headers will fit.
+ // This means that a particularly long header might close out the header queue where later
+ // headers could still fit. We could in the future alter the behavior here based on prerender vs render
+ // since during prerender we aren't as concerned with pure runtime performance.
+
+ if ((headers.remainingCapacity -= header.length) >= 2) {
+ renderState.resets.style[key] = PRELOAD_NO_CREDS;
+
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += header; // We already track that the resource exists in resumableState however
+ // if the resumableState resets because we postponed in the shell
+ // which is what is happening in this branch if we are prerendering
+ // then we will end up resetting the resumableState. When it resets we
+ // want to record the fact that this stylesheet was already preloaded
+
+ renderState.resets.style[key] = typeof props.crossOrigin === 'string' || typeof props.integrity === 'string' ? [props.crossOrigin, props.integrity] : PRELOAD_NO_CREDS;
+ } else {
+ break outer;
+ }
+ }
+ }
+ }
+
+ if (linkHeader) {
+ onHeaders({
+ Link: linkHeader
+ });
+ } else {
+ // We still call this with no headers because a user may be using it as a signal that
+ // it React will not provide any headers
+ onHeaders({});
+ }
+
+ renderState.headers = null;
+ return;
+ }
+ }
+}
+const NotPendingTransition = NotPending;
+
+// ATTENTION
+// When adding new symbols to this file,
+// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
+// The Symbol used to tag the ReactElement-like types.
+const REACT_ELEMENT_TYPE = Symbol.for('react.element');
+const REACT_PORTAL_TYPE = Symbol.for('react.portal');
+const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
+const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
+const REACT_PROFILER_TYPE = Symbol.for('react.profiler');
+const REACT_PROVIDER_TYPE = Symbol.for('react.provider');
+const REACT_CONTEXT_TYPE = Symbol.for('react.context');
+const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
+const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
+const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
+const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
+const REACT_MEMO_TYPE = Symbol.for('react.memo');
+const REACT_LAZY_TYPE = Symbol.for('react.lazy');
+const REACT_SCOPE_TYPE = Symbol.for('react.scope');
+const REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');
+const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
+const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');
+const REACT_CACHE_TYPE = Symbol.for('react.cache');
+const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value');
+const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
+const FAUX_ITERATOR_SYMBOL = '@@iterator';
+function getIteratorFn(maybeIterable) {
+ if (maybeIterable === null || typeof maybeIterable !== 'object') {
+ return null;
+ }
+
+ const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
+
+ if (typeof maybeIterator === 'function') {
+ return maybeIterator;
+ }
+
+ return null;
+}
+
+function getWrappedName(outerType, innerType, wrapperName) {
+ const displayName = outerType.displayName;
+
+ if (displayName) {
+ return displayName;
+ }
+
+ const functionName = innerType.displayName || innerType.name || '';
+ return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName;
+} // Keep in sync with react-reconciler/getComponentNameFromFiber
+
+
+function getContextName(type) {
+ return type.displayName || 'Context';
+} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+
+
+function getComponentNameFromType(type) {
+ if (type == null) {
+ // Host root, text node or just invalid type.
+ return null;
+ }
+
+ if (typeof type === 'function') {
+ return type.displayName || type.name || null;
+ }
+
+ if (typeof type === 'string') {
+ return type;
+ }
+
+ switch (type) {
+ case REACT_FRAGMENT_TYPE:
+ return 'Fragment';
+
+ case REACT_PORTAL_TYPE:
+ return 'Portal';
+
+ case REACT_PROFILER_TYPE:
+ return 'Profiler';
+
+ case REACT_STRICT_MODE_TYPE:
+ return 'StrictMode';
+
+ case REACT_SUSPENSE_TYPE:
+ return 'Suspense';
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ return 'SuspenseList';
+
+ case REACT_CACHE_TYPE:
+ {
+ return 'Cache';
+ }
+
+ }
+
+ if (typeof type === 'object') {
+ switch (type.$$typeof) {
+ case REACT_CONTEXT_TYPE:
+ const context = type;
+ return getContextName(context) + '.Consumer';
+
+ case REACT_PROVIDER_TYPE:
+ const provider = type;
+ return getContextName(provider._context) + '.Provider';
+
+ case REACT_FORWARD_REF_TYPE:
+ return getWrappedName(type, type.render, 'ForwardRef');
+
+ case REACT_MEMO_TYPE:
+ const outerName = type.displayName || null;
+
+ if (outerName !== null) {
+ return outerName;
+ }
+
+ return getComponentNameFromType(type.type) || 'Memo';
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyComponent = type;
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+
+ try {
+ return getComponentNameFromType(init(payload));
+ } catch (x) {
+ return null;
+ }
+ }
+
+ }
+ }
+
+ return null;
+}
+
+const emptyContextObject = {};
+
+function getMaskedContext(type, unmaskedContext) {
+ {
+ const contextTypes = type.contextTypes;
+
+ if (!contextTypes) {
+ return emptyContextObject;
+ }
+
+ const context = {};
+
+ for (const key in contextTypes) {
+ context[key] = unmaskedContext[key];
+ }
+
+ return context;
+ }
+}
+function processChildContext(instance, type, parentContext, childContextTypes) {
+ {
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
+ if (typeof instance.getChildContext !== 'function') {
+
+ return parentContext;
+ }
+
+ const childContext = instance.getChildContext();
+
+ for (const contextKey in childContext) {
+ if (!(contextKey in childContextTypes)) {
+ throw new Error((getComponentNameFromType(type) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes.");
+ }
+ }
+
+ return assign({}, parentContext, childContext);
+ }
+}
+
+// Forming a reverse tree.
+// The structure of a context snapshot is an implementation of this file.
+// Currently, it's implemented as tracking the current active node.
+
+
+const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
+// This global (actually thread local) state represents what state all those "current",
+// fields are currently in.
+
+let currentActiveSnapshot = null;
+
+function popNode(prev) {
+ {
+ prev.context._currentValue = prev.parentValue;
+ }
+}
+
+function pushNode(next) {
+ {
+ next.context._currentValue = next.value;
+ }
+}
+
+function popToNearestCommonAncestor(prev, next) {
+ if (prev === next) ; else {
+ popNode(prev);
+ const parentPrev = prev.parent;
+ const parentNext = next.parent;
+
+ if (parentPrev === null) {
+ if (parentNext !== null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+ } else {
+ if (parentNext === null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+
+ popToNearestCommonAncestor(parentPrev, parentNext);
+ } // On the way back, we push the new ones that weren't common.
+
+
+ pushNode(next);
+ }
+}
+
+function popAllPrevious(prev) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev !== null) {
+ popAllPrevious(parentPrev);
+ }
+}
+
+function pushAllNext(next) {
+ const parentNext = next.parent;
+
+ if (parentNext !== null) {
+ pushAllNext(parentNext);
+ }
+
+ pushNode(next);
+}
+
+function popPreviousToCommonLevel(prev, next) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (parentPrev.depth === next.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(parentPrev, next);
+ } else {
+ // We must still be deeper.
+ popPreviousToCommonLevel(parentPrev, next);
+ }
+}
+
+function popNextToCommonLevel(prev, next) {
+ const parentNext = next.parent;
+
+ if (parentNext === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (prev.depth === parentNext.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(prev, parentNext);
+ } else {
+ // We must still be deeper.
+ popNextToCommonLevel(prev, parentNext);
+ }
+
+ pushNode(next);
+} // Perform context switching to the new snapshot.
+// To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
+// updating all the context's current values. That way reads, always just read the current value.
+// At the cost of updating contexts even if they're never read by this subtree.
+
+
+function switchContext(newSnapshot) {
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
+ // We also need to update any new contexts that are now on the stack with the deepest value.
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
+ // for that. Therefore this algorithm is recursive.
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
+ // 3) Then we reapply new contexts on the way back up the stack.
+ const prev = currentActiveSnapshot;
+ const next = newSnapshot;
+
+ if (prev !== next) {
+ if (prev === null) {
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
+ pushAllNext(next);
+ } else if (next === null) {
+ popAllPrevious(prev);
+ } else if (prev.depth === next.depth) {
+ popToNearestCommonAncestor(prev, next);
+ } else if (prev.depth > next.depth) {
+ popPreviousToCommonLevel(prev, next);
+ } else {
+ popNextToCommonLevel(prev, next);
+ }
+
+ currentActiveSnapshot = next;
+ }
+}
+function pushProvider(context, nextValue) {
+ let prevValue;
+
+ {
+ prevValue = context._currentValue;
+ context._currentValue = nextValue;
+ }
+
+ const prevNode = currentActiveSnapshot;
+ const newNode = {
+ parent: prevNode,
+ depth: prevNode === null ? 0 : prevNode.depth + 1,
+ context: context,
+ parentValue: prevValue,
+ value: nextValue
+ };
+ currentActiveSnapshot = newNode;
+ return newNode;
+}
+function popProvider(context) {
+ const prevSnapshot = currentActiveSnapshot;
+
+ if (prevSnapshot === null) {
+ throw new Error('Tried to pop a Context at the root of the app. This is a bug in React.');
+ }
+
+ {
+ const value = prevSnapshot.parentValue;
+
+ if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) {
+ prevSnapshot.context._currentValue = prevSnapshot.context._defaultValue;
+ } else {
+ prevSnapshot.context._currentValue = value;
+ }
+ }
+
+ return currentActiveSnapshot = prevSnapshot.parent;
+}
+function getActiveContext() {
+ return currentActiveSnapshot;
+}
+function readContext$1(context) {
+ const value = context._currentValue ;
+ return value;
+}
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ *
+ * Note that this module is currently shared and assumed to be stateless.
+ * If this becomes an actual Map, that will break.
+ */
+function get(key) {
+ return key._reactInternals;
+}
+function set(key, value) {
+ key._reactInternals = value;
+}
+
+const classComponentUpdater = {
+ isMounted(inst) {
+ return false;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueSetState(inst, payload, callback) {
+ const internals = get(inst);
+
+ if (internals.queue === null) ; else {
+ internals.queue.push(payload);
+ }
+ },
+
+ enqueueReplaceState(inst, payload, callback) {
+ const internals = get(inst);
+ internals.replace = true;
+ internals.queue = [payload];
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueForceUpdate(inst, callback) {
+ }
+
+};
+
+function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) {
+ const partialState = getDerivedStateFromProps(nextProps, prevState);
+
+
+ const newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);
+ return newState;
+}
+
+function constructClassInstance(ctor, props, maskedLegacyContext) {
+ let context = emptyContextObject;
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ context = readContext$1(contextType);
+ } else {
+ context = maskedLegacyContext;
+ }
+
+ const instance = new ctor(props, context);
+
+ return instance;
+}
+
+function callComponentWillMount(type, instance) {
+ const oldState = instance.state;
+
+ if (typeof instance.componentWillMount === 'function') {
+
+ instance.componentWillMount();
+ }
+
+ if (typeof instance.UNSAFE_componentWillMount === 'function') {
+ instance.UNSAFE_componentWillMount();
+ }
+
+ if (oldState !== instance.state) {
+
+ classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
+ }
+}
+
+function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) {
+ if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
+ const oldQueue = internalInstance.queue;
+ const oldReplace = internalInstance.replace;
+ internalInstance.queue = null;
+ internalInstance.replace = false;
+
+ if (oldReplace && oldQueue.length === 1) {
+ inst.state = oldQueue[0];
+ } else {
+ let nextState = oldReplace ? oldQueue[0] : inst.state;
+ let dontMutate = true;
+
+ for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
+ const partial = oldQueue[i];
+ const partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial;
+
+ if (partialState != null) {
+ if (dontMutate) {
+ dontMutate = false;
+ nextState = assign({}, nextState, partialState);
+ } else {
+ assign(nextState, partialState);
+ }
+ }
+ }
+
+ inst.state = nextState;
+ }
+ } else {
+ internalInstance.queue = null;
+ }
+} // Invokes the mount life-cycles on a previously never rendered instance.
+
+
+function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) {
+
+ const initialState = instance.state !== undefined ? instance.state : null;
+ instance.updater = classComponentUpdater;
+ instance.props = newProps;
+ instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway.
+ // The internal instance will be used to manage updates that happen during this mount.
+
+ const internalInstance = {
+ queue: [],
+ replace: false
+ };
+ set(instance, internalInstance);
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ instance.context = readContext$1(contextType);
+ } else {
+ instance.context = maskedLegacyContext;
+ }
+
+ const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
+
+ if (typeof getDerivedStateFromProps === 'function') {
+ instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps);
+ } // In order to support react-lifecycles-compat polyfilled components,
+ // Unsafe lifecycles should not be invoked for components using the new APIs.
+
+
+ if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
+ callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's
+ // process them now.
+
+ processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext);
+ }
+}
+
+// Ids are base 32 strings whose binary representation corresponds to the
+// position of a node in a tree.
+// Every time the tree forks into multiple children, we add additional bits to
+// the left of the sequence that represent the position of the child within the
+// current level of children.
+//
+// 00101 00010001011010101
+// ╰─┬─╯ ╰───────┬───────╯
+// Fork 5 of 20 Parent id
+//
+// The leading 0s are important. In the above example, you only need 3 bits to
+// represent slot 5. However, you need 5 bits to represent all the forks at
+// the current level, so we must account for the empty bits at the end.
+//
+// For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise,
+// the zeroth id at a level would be indistinguishable from its parent.
+//
+// If a node has only one child, and does not materialize an id (i.e. does not
+// contain a useId hook), then we don't need to allocate any space in the
+// sequence. It's treated as a transparent indirection. For example, these two
+// trees produce the same ids:
+//
+// <> <>
+//
+//
+// >
+//
+// >
+//
+// However, we cannot skip any node that materializes an id. Otherwise, a parent
+// id that does not fork would be indistinguishable from its child id. For
+// example, this tree does not fork, but the parent and child must have
+// different ids.
+//
+//
+//
+//
+//
+// To handle this scenario, every time we materialize an id, we allocate a
+// new level with a single slot. You can think of this as a fork with only one
+// prong, or an array of children with length 1.
+//
+// It's possible for the size of the sequence to exceed 32 bits, the max
+// size for bitwise operations. When this happens, we make more room by
+// converting the right part of the id to a string and storing it in an overflow
+// variable. We use a base 32 string representation, because 32 is the largest
+// power of 2 that is supported by toString(). We want the base to be large so
+// that the resulting ids are compact, and we want the base to be a power of 2
+// because every log2(base) bits corresponds to a single character, i.e. every
+// log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without
+// affecting the final result.
+const emptyTreeContext = {
+ id: 1,
+ overflow: ''
+};
+function getTreeId(context) {
+ const overflow = context.overflow;
+ const idWithLeadingBit = context.id;
+ const id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);
+ return id.toString(32) + overflow;
+}
+function pushTreeContext(baseContext, totalChildren, index) {
+ const baseIdWithLeadingBit = baseContext.id;
+ const baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part
+ // of the id; we use it to account for leading 0s.
+
+ const baseLength = getBitLength(baseIdWithLeadingBit) - 1;
+ const baseId = baseIdWithLeadingBit & ~(1 << baseLength);
+ const slot = index + 1;
+ const length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into
+ // consideration the leading 1 we use to mark the end of the sequence.
+
+ if (length > 30) {
+ // We overflowed the bitwise-safe range. Fall back to slower algorithm.
+ // This branch assumes the length of the base id is greater than 5; it won't
+ // work for smaller ids, because you need 5 bits per character.
+ //
+ // We encode the id in multiple steps: first the base id, then the
+ // remaining digits.
+ //
+ // Each 5 bit sequence corresponds to a single base 32 character. So for
+ // example, if the current id is 23 bits long, we can convert 20 of those
+ // bits into a string of 4 characters, with 3 bits left over.
+ //
+ // First calculate how many bits in the base id represent a complete
+ // sequence of characters.
+ const numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.
+
+ const newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.
+
+ const newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.
+
+ const restOfBaseId = baseId >> numberOfOverflowBits;
+ const restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because
+ // we made more room, this time it won't overflow.
+
+ const restOfLength = getBitLength(totalChildren) + restOfBaseLength;
+ const restOfNewBits = slot << restOfBaseLength;
+ const id = restOfNewBits | restOfBaseId;
+ const overflow = newOverflow + baseOverflow;
+ return {
+ id: 1 << restOfLength | id,
+ overflow
+ };
+ } else {
+ // Normal path
+ const newBits = slot << baseLength;
+ const id = newBits | baseId;
+ const overflow = baseOverflow;
+ return {
+ id: 1 << length | id,
+ overflow
+ };
+ }
+}
+
+function getBitLength(number) {
+ return 32 - clz32(number);
+}
+
+function getLeadingBit(id) {
+ return 1 << getBitLength(id) - 1;
+} // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback.
+
+
+const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.
+// Based on:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+const log = Math.log;
+const LN2 = Math.LN2;
+
+function clz32Fallback(x) {
+ const asUint = x >>> 0;
+
+ if (asUint === 0) {
+ return 32;
+ }
+
+ return 31 - (log(asUint) / LN2 | 0) | 0;
+}
+
+// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
+// changes to one module should be reflected in the others.
+// TODO: Rename this module and the corresponding Fiber one to "Thenable"
+// instead of "Wakeable". Or some other more appropriate name.
+// An error that is thrown (e.g. by `use`) to trigger Suspense. If we
+// detect this is caught by userspace, we'll log a warning in development.
+const SuspenseException = new Error("Suspense Exception: This is not a real error! It's an implementation " + 'detail of `use` to interrupt the current render. You must either ' + 'rethrow it immediately, or move the `use` call outside of the ' + '`try/catch` block. Capturing without rethrowing will lead to ' + 'unexpected behavior.\n\n' + 'To handle async errors, wrap your component in an error boundary, or ' + "call the promise's `.catch` method and pass the result to `use`");
+function createThenableState() {
+ // The ThenableState is created the first time a component suspends. If it
+ // suspends again, we'll reuse the same state.
+ return [];
+}
+
+function noop$2() {}
+
+function trackUsedThenable(thenableState, thenable, index) {
+ const previous = thenableState[index];
+
+ if (previous === undefined) {
+ thenableState.push(thenable);
+ } else {
+ if (previous !== thenable) {
+ // Reuse the previous thenable, and drop the new one. We can assume
+ // they represent the same value, because components are idempotent.
+ // Avoid an unhandled rejection errors for the Promises that we'll
+ // intentionally ignore.
+ thenable.then(noop$2, noop$2);
+ thenable = previous;
+ }
+ } // We use an expando to track the status and result of a thenable so that we
+ // can synchronously unwrap the value. Think of this as an extension of the
+ // Promise API, or a custom interface that is a superset of Thenable.
+ //
+ // If the thenable doesn't have a status, set it to "pending" and attach
+ // a listener that will update its status and result when it resolves.
+
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledValue = thenable.value;
+ return fulfilledValue;
+ }
+
+ case 'rejected':
+ {
+ const rejectedError = thenable.reason;
+ throw rejectedError;
+ }
+
+ default:
+ {
+ if (typeof thenable.status === 'string') ; else {
+ const pendingThenable = thenable;
+ pendingThenable.status = 'pending';
+ pendingThenable.then(fulfilledValue => {
+ if (thenable.status === 'pending') {
+ const fulfilledThenable = thenable;
+ fulfilledThenable.status = 'fulfilled';
+ fulfilledThenable.value = fulfilledValue;
+ }
+ }, error => {
+ if (thenable.status === 'pending') {
+ const rejectedThenable = thenable;
+ rejectedThenable.status = 'rejected';
+ rejectedThenable.reason = error;
+ }
+ }); // Check one more time in case the thenable resolved synchronously
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledThenable = thenable;
+ return fulfilledThenable.value;
+ }
+
+ case 'rejected':
+ {
+ const rejectedThenable = thenable;
+ throw rejectedThenable.reason;
+ }
+ }
+ } // Suspend.
+ //
+ // Throwing here is an implementation detail that allows us to unwind the
+ // call stack. But we shouldn't allow it to leak into userspace. Throw an
+ // opaque placeholder value instead of the actual thenable. If it doesn't
+ // get captured by the work loop, log a warning, because that means
+ // something in userspace must have caught it.
+
+
+ suspendedThenable = thenable;
+ throw SuspenseException;
+ }
+ }
+} // This is used to track the actual thenable that suspended so it can be
+// passed to the rest of the Suspense implementation — which, for historical
+// reasons, expects to receive a thenable.
+
+let suspendedThenable = null;
+function getSuspendedThenable() {
+ // This is called right after `use` suspends by throwing an exception. `use`
+ // throws an opaque value instead of the thenable itself so that it can't be
+ // caught in userspace. Then the work loop accesses the actual thenable using
+ // this function.
+ if (suspendedThenable === null) {
+ throw new Error('Expected a suspended thenable. This is a bug in React. Please file ' + 'an issue.');
+ }
+
+ const thenable = suspendedThenable;
+ suspendedThenable = null;
+ return thenable;
+}
+
+/**
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+ */
+function is(x, y) {
+ return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
+ ;
+}
+
+const objectIs = // $FlowFixMe[method-unbinding]
+typeof Object.is === 'function' ? Object.is : is;
+
+let currentlyRenderingComponent = null;
+let currentlyRenderingTask = null;
+let currentlyRenderingRequest = null;
+let currentlyRenderingKeyPath = null;
+let firstWorkInProgressHook = null;
+let workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook
+
+let isReRender = false; // Whether an update was scheduled during the currently executing render pass.
+
+let didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component
+
+let localIdCounter = 0; // Chunks that should be pushed to the stream once the component
+// finishes rendering.
+// Counts the number of useFormState calls in this component
+
+let formStateCounter = 0; // The index of the useFormState hook that matches the one passed in at the
+// root during an MPA navigation, if any.
+
+let formStateMatchingIndex = -1; // Counts the number of use(thenable) calls in this component
+
+let thenableIndexCounter = 0;
+let thenableState = null; // Lazily created map of render-phase updates
+
+let renderPhaseUpdates = null; // Counter to prevent infinite loops.
+
+let numberOfReRenders = 0;
+const RE_RENDER_LIMIT = 25;
+
+function resolveCurrentlyRenderingComponent() {
+ if (currentlyRenderingComponent === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + '2. You might be breaking the Rules of Hooks\n' + '3. You might have more than one copy of React in the same app\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.');
+ }
+
+ return currentlyRenderingComponent;
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+
+ return false;
+ }
+
+
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ if (objectIs(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+function createHook() {
+ if (numberOfReRenders > 0) {
+ throw new Error('Rendered more hooks than during the previous render');
+ }
+
+ return {
+ memoizedState: null,
+ queue: null,
+ next: null
+ };
+}
+
+function createWorkInProgressHook() {
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ if (firstWorkInProgressHook === null) {
+ isReRender = false;
+ firstWorkInProgressHook = workInProgressHook = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = firstWorkInProgressHook;
+ }
+ } else {
+ if (workInProgressHook.next === null) {
+ isReRender = false; // Append to the end of the list
+
+ workInProgressHook = workInProgressHook.next = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = workInProgressHook.next;
+ }
+ }
+
+ return workInProgressHook;
+}
+
+function prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState) {
+ currentlyRenderingComponent = componentIdentity;
+ currentlyRenderingTask = task;
+ currentlyRenderingRequest = request;
+ currentlyRenderingKeyPath = keyPath;
+ // didScheduleRenderPhaseUpdate = false;
+ // firstWorkInProgressHook = null;
+ // numberOfReRenders = 0;
+ // renderPhaseUpdates = null;
+ // workInProgressHook = null;
+
+
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ thenableState = prevThenableState;
+}
+function finishHooks(Component, props, children, refOrContext) {
+ // This must be called after every function component to prevent hooks from
+ // being used in classes.
+ while (didScheduleRenderPhaseUpdate) {
+ // Updates were scheduled during the render phase. They are stored in
+ // the `renderPhaseUpdates` map. Call the component again, reusing the
+ // work-in-progress hooks and applying the additional updates on top. Keep
+ // restarting until no more updates are scheduled.
+ didScheduleRenderPhaseUpdate = false;
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ numberOfReRenders += 1; // Start over from the beginning of the list
+
+ workInProgressHook = null;
+ children = Component(props, refOrContext);
+ }
+
+ resetHooksState();
+ return children;
+}
+function getThenableStateAfterSuspending() {
+ const state = thenableState;
+ thenableState = null;
+ return state;
+}
+function checkDidRenderIdHook() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ const didRenderIdHook = localIdCounter !== 0;
+ return didRenderIdHook;
+}
+function getFormStateCount() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateCounter;
+}
+function getFormStateMatchingIndex() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateMatchingIndex;
+} // Reset the internal hooks state if an error occurs while rendering a component
+
+function resetHooksState() {
+
+ currentlyRenderingComponent = null;
+ currentlyRenderingTask = null;
+ currentlyRenderingRequest = null;
+ currentlyRenderingKeyPath = null;
+ didScheduleRenderPhaseUpdate = false;
+ firstWorkInProgressHook = null;
+ numberOfReRenders = 0;
+ renderPhaseUpdates = null;
+ workInProgressHook = null;
+}
+
+function readContext(context) {
+
+ return readContext$1(context);
+}
+
+function useContext(context) {
+
+ resolveCurrentlyRenderingComponent();
+ return readContext$1(context);
+}
+
+function basicStateReducer(state, action) {
+ // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
+ return typeof action === 'function' ? action(state) : action;
+}
+
+function useState(initialState) {
+
+ return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers
+ initialState);
+}
+function useReducer(reducer, initialArg, init) {
+
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+
+ if (isReRender) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ // current hook.
+ const queue = workInProgressHook.queue;
+ const dispatch = queue.dispatch;
+
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate !== undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.delete(queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ let newState = workInProgressHook.memoizedState;
+ let update = firstRenderPhaseUpdate;
+
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ const action = update.action;
+
+ newState = reducer(newState, action);
+
+
+ update = update.next;
+ } while (update !== null); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ workInProgressHook.memoizedState = newState;
+ return [newState, dispatch];
+ }
+ } // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ return [workInProgressHook.memoizedState, dispatch];
+ } else {
+
+ let initialState;
+
+ if (reducer === basicStateReducer) {
+ // Special case for `useState`.
+ initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
+ } else {
+ initialState = init !== undefined ? init(initialArg) : initialArg;
+ }
+
+
+ workInProgressHook.memoizedState = initialState; // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ const queue = workInProgressHook.queue = {
+ last: null,
+ dispatch: null
+ };
+ const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ return [workInProgressHook.memoizedState, dispatch];
+ }
+}
+
+function useMemo(nextCreate, deps) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const nextDeps = deps === undefined ? null : deps;
+
+ if (workInProgressHook !== null) {
+ const prevState = workInProgressHook.memoizedState;
+
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ const prevDeps = prevState[1];
+
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ }
+
+ const nextValue = nextCreate();
+
+
+ workInProgressHook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function useRef(initialValue) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const previousRef = workInProgressHook.memoizedState;
+
+ if (previousRef === null) {
+ const ref = {
+ current: initialValue
+ };
+
+
+ workInProgressHook.memoizedState = ref;
+ return ref;
+ } else {
+ return previousRef;
+ }
+}
+
+function dispatchAction(componentIdentity, queue, action) {
+ if (numberOfReRenders >= RE_RENDER_LIMIT) {
+ throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.');
+ }
+
+ if (componentIdentity === currentlyRenderingComponent) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ const update = {
+ action,
+ next: null
+ };
+
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate === undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+
+ lastRenderPhaseUpdate.next = update;
+ }
+ }
+}
+
+function useCallback(callback, deps) {
+ return useMemo(() => callback, deps);
+}
+
+function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
+ if (getServerSnapshot === undefined) {
+ throw new Error('Missing getServerSnapshot, which is required for ' + 'server-rendered content. Will revert to client rendering.');
+ }
+
+ return getServerSnapshot();
+}
+
+function useDeferredValue(value, initialValue) {
+ resolveCurrentlyRenderingComponent();
+
+ {
+ return value;
+ }
+}
+
+function unsupportedStartTransition() {
+ throw new Error('startTransition cannot be called during server rendering.');
+}
+
+function useTransition() {
+ resolveCurrentlyRenderingComponent();
+ return [false, unsupportedStartTransition];
+}
+
+function useHostTransitionStatus() {
+ resolveCurrentlyRenderingComponent();
+ return NotPendingTransition;
+}
+
+function unsupportedSetOptimisticState() {
+ throw new Error('Cannot update optimistic state while rendering.');
+}
+
+function useOptimistic(passthrough, reducer) {
+ resolveCurrentlyRenderingComponent();
+ return [passthrough, unsupportedSetOptimisticState];
+}
+
+function createPostbackFormStateKey(permalink, componentKeyPath, hookIndex) {
+ if (permalink !== undefined) {
+ // Don't bother to hash a permalink-based key since it's already short.
+ return 'p' + permalink;
+ } else {
+ // Append a node to the key path that represents the form state hook.
+ const keyPath = [componentKeyPath, null, hookIndex]; // Key paths are hashed to reduce the size. It does not need to be secure,
+ // and it's more important that it's fast than that it's completely
+ // collision-free.
+
+ const keyPathHash = createFastHash(JSON.stringify(keyPath));
+ return 'k' + keyPathHash;
+ }
+}
+
+function useFormState(action, initialState, permalink) {
+ resolveCurrentlyRenderingComponent(); // Count the number of useFormState hooks per component. We also use this to
+ // track the position of this useFormState hook relative to the other ones in
+ // this component, so we can generate a unique key for each one.
+
+ const formStateHookIndex = formStateCounter++;
+ const request = currentlyRenderingRequest; // $FlowIgnore[prop-missing]
+
+ const formAction = action.$$FORM_ACTION;
+
+ if (typeof formAction === 'function') {
+ // This is a server action. These have additional features to enable
+ // MPA-style form submissions with progressive enhancement.
+ // TODO: If the same permalink is passed to multiple useFormStates, and
+ // they all have the same action signature, Fizz will pass the postback
+ // state to all of them. We should probably only pass it to the first one,
+ // and/or warn.
+ // The key is lazily generated and deduped so the that the keypath doesn't
+ // get JSON.stringify-ed unnecessarily, and at most once.
+ let nextPostbackStateKey = null; // Determine the current form state. If we received state during an MPA form
+ // submission, then we will reuse that, if the action identity matches.
+ // Otherwise we'll use the initial state argument. We will emit a comment
+ // marker into the stream that indicates whether the state was reused.
+
+ let state = initialState;
+ const componentKeyPath = currentlyRenderingKeyPath;
+ const postbackFormState = getFormState(request); // $FlowIgnore[prop-missing]
+
+ const isSignatureEqual = action.$$IS_SIGNATURE_EQUAL;
+
+ if (postbackFormState !== null && typeof isSignatureEqual === 'function') {
+ const postbackKey = postbackFormState[1];
+ const postbackReferenceId = postbackFormState[2];
+ const postbackBoundArity = postbackFormState[3];
+
+ if (isSignatureEqual.call(action, postbackReferenceId, postbackBoundArity)) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+
+ if (postbackKey === nextPostbackStateKey) {
+ // This was a match
+ formStateMatchingIndex = formStateHookIndex; // Reuse the state that was submitted by the form.
+
+ state = postbackFormState[0];
+ }
+ }
+ } // Bind the state to the first argument of the action.
+
+
+ const boundAction = action.bind(null, state); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ }; // $FlowIgnore[prop-missing]
+
+
+ if (typeof boundAction.$$FORM_ACTION === 'function') {
+ // $FlowIgnore[prop-missing]
+ dispatch.$$FORM_ACTION = prefix => {
+ const metadata = boundAction.$$FORM_ACTION(prefix); // Override the action URL
+
+ if (permalink !== undefined) {
+
+ permalink += '';
+ metadata.action = permalink;
+ }
+
+ const formData = metadata.data;
+
+ if (formData) {
+ if (nextPostbackStateKey === null) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+ }
+
+ formData.append('$ACTION_KEY', nextPostbackStateKey);
+ }
+
+ return metadata;
+ };
+ }
+
+ return [state, dispatch];
+ } else {
+ // This is not a server action, so the implementation is much simpler.
+ // Bind the state to the first argument of the action.
+ const boundAction = action.bind(null, initialState); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ };
+
+ return [initialState, dispatch];
+ }
+}
+
+function useId() {
+ const task = currentlyRenderingTask;
+ const treeId = getTreeId(task.treeContext);
+ const resumableState = currentResumableState;
+
+ if (resumableState === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component.');
+ }
+
+ const localId = localIdCounter++;
+ return makeId(resumableState, treeId, localId);
+}
+
+function use(usable) {
+ if (usable !== null && typeof usable === 'object') {
+ // $FlowFixMe[method-unbinding]
+ if (typeof usable.then === 'function') {
+ // This is a thenable.
+ const thenable = usable;
+ return unwrapThenable(thenable);
+ } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = usable;
+ return readContext(context);
+ }
+ } // eslint-disable-next-line react-internal/safe-string-coercion
+
+
+ throw new Error('An unsupported type was passed to use(): ' + String(usable));
+}
+
+function unwrapThenable(thenable) {
+ const index = thenableIndexCounter;
+ thenableIndexCounter += 1;
+
+ if (thenableState === null) {
+ thenableState = createThenableState();
+ }
+
+ return trackUsedThenable(thenableState, thenable, index);
+}
+
+function unsupportedRefresh() {
+ throw new Error('Cache cannot be refreshed during server rendering.');
+}
+
+function useCacheRefresh() {
+ return unsupportedRefresh;
+}
+
+function noop$1() {}
+
+const HooksDispatcher = {
+ readContext,
+ use,
+ useContext,
+ useMemo,
+ useReducer,
+ useRef,
+ useState,
+ useInsertionEffect: noop$1,
+ useLayoutEffect: noop$1,
+ useCallback,
+ // useImperativeHandle is not run in the server environment
+ useImperativeHandle: noop$1,
+ // Effects are not run in the server environment.
+ useEffect: noop$1,
+ // Debugging effect
+ useDebugValue: noop$1,
+ useDeferredValue,
+ useTransition,
+ useId,
+ // Subscriptions are not setup in a server environment.
+ useSyncExternalStore
+};
+
+{
+ HooksDispatcher.useCacheRefresh = useCacheRefresh;
+}
+
+{
+ HooksDispatcher.useHostTransitionStatus = useHostTransitionStatus;
+}
+
+{
+ HooksDispatcher.useOptimistic = useOptimistic;
+ HooksDispatcher.useFormState = useFormState;
+}
+
+let currentResumableState = null;
+function setCurrentResumableState(resumableState) {
+ currentResumableState = resumableState;
+}
+
+function getCacheSignal() {
+ throw new Error('Not implemented.');
+}
+
+function getCacheForType(resourceType) {
+ throw new Error('Not implemented.');
+}
+
+const DefaultCacheDispatcher = {
+ getCacheSignal,
+ getCacheForType
+};
+
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
+const ReactCurrentCache = ReactSharedInternals.ReactCurrentCache;
+// The name might be minified but we assume that it's going to be the same generated name. Typically
+// because it's just the same compiled output in practice.
+// resume with segmentID at the index
+
+const CLIENT_RENDERED = 4; // if it errors or infinitely suspends
+
+const PENDING = 0;
+const COMPLETED = 1;
+const FLUSHED = 2;
+const ABORTED = 3;
+const ERRORED = 4;
+const POSTPONED = 5;
+const OPEN = 0;
+const CLOSING = 1;
+const CLOSED = 2; // This is a default heuristic for how to split up the HTML content into progressive
+// loading. Our goal is to be able to display additional new content about every 500ms.
+// Faster than that is unnecessary and should be throttled on the client. It also
+// adds unnecessary overhead to do more splits. We don't know if it's a higher or lower
+// end device but higher end suffer less from the overhead than lower end does from
+// not getting small enough pieces. We error on the side of low end.
+// We base this on low end 3G speeds which is about 500kbits per second. We assume
+// that there can be a reasonable drop off from max bandwidth which leaves you with
+// as little as 80%. We can receive half of that each 500ms - at best. In practice,
+// a little bandwidth is lost to processing and contention - e.g. CSS and images that
+// are downloaded along with the main content. So we estimate about half of that to be
+// the lower end throughput. In other words, we expect that you can at least show
+// about 12.5kb of content per 500ms. Not counting starting latency for the first
+// paint.
+// 500 * 1024 / 8 * .8 * 0.5 / 2
+
+const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
+
+function defaultErrorHandler(error) {
+ console['error'](error); // Don't transform to our wrapper
+
+ return null;
+}
+
+function noop() {}
+
+function createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, formState) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState,
+ renderState,
+ rootFormatContext,
+ progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: 0,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: formState === undefined ? null : formState
+ }; // This segment represents the root fallback.
+
+ const rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false); // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+let currentRequest = null;
+function resolveRequest() {
+ if (currentRequest) return currentRequest;
+
+ return null;
+}
+
+function pingTask(request, task) {
+ const pingedTasks = request.pingedTasks;
+ pingedTasks.push(task);
+
+ if (request.pingedTasks.length === 1) {
+ request.flushScheduled = request.destination !== null;
+ scheduleWork(() => performWork(request));
+ }
+}
+
+function createSuspenseBoundary(request, fallbackAbortableTasks) {
+ return {
+ status: PENDING,
+ rootSegmentID: -1,
+ parentFlushed: false,
+ pendingTasks: 0,
+ completedSegments: [],
+ byteSize: 0,
+ fallbackAbortableTasks,
+ errorDigest: null,
+ resources: createBoundaryResources(),
+ trackedContentKeyPath: null,
+ trackedFallbackNode: null
+ };
+}
+
+function createRenderTask(request, thenableState, node, childIndex, blockedBoundary, blockedSegment, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ const task = {
+ replay: null,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createReplayTask(request, thenableState, replay, node, childIndex, blockedBoundary, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ replay.pendingTasks++;
+ const task = {
+ replay,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment: null,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createPendingSegment(request, index, boundary, parentFormatContext, lastPushedText, textEmbedded) {
+ return {
+ status: PENDING,
+ id: -1,
+ // lazily assigned later
+ index,
+ parentFlushed: false,
+ chunks: [],
+ children: [],
+ parentFormatContext,
+ boundary,
+ lastPushedText,
+ textEmbedded
+ };
+} // DEV-only global reference to the currently executing task
+
+function popComponentStackInDEV(task) {
+} // stash the component stack of an unwinding error until it is processed
+
+function logRecoverableError(request, error) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ const errorDigest = request.onError(error);
+
+ if (errorDigest != null && typeof errorDigest !== 'string') {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead");
+ }
+
+ return errorDigest;
+}
+
+function fatalError(request, error) {
+ // This is called outside error handling code such as if the root errors outside
+ // a suspense boundary or if the root suspense boundary's fallback errors.
+ // It's also called if React itself or its host configs errors.
+ const onShellError = request.onShellError;
+ onShellError(error);
+ const onFatalError = request.onFatalError;
+ onFatalError(error);
+
+ if (request.destination !== null) {
+ request.status = CLOSED;
+ closeWithError(request.destination, error);
+ } else {
+ request.status = CLOSING;
+ request.fatalError = error;
+ }
+}
+
+function renderSuspenseBoundary(request, someTask, keyPath, props) {
+ if (someTask.replay !== null) {
+ // If we're replaying through this pass, it means we're replaying through
+ // an already completed Suspense boundary. It's too late to do anything about it
+ // so we can just render through it.
+ const prevKeyPath = someTask.keyPath;
+ someTask.keyPath = keyPath;
+ const content = props.children;
+
+ try {
+ renderNode(request, someTask, content, -1);
+ } finally {
+ someTask.keyPath = prevKeyPath;
+ }
+
+ return;
+ } // $FlowFixMe: Refined.
+
+
+ const task = someTask;
+ const prevKeyPath = task.keyPath;
+ const parentBoundary = task.blockedBoundary;
+ const parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for
+ // the fallback so that we can later replace that segment with the content.
+ // This also lets us split out the main content even if it doesn't suspend,
+ // in case it ends up generating a large subtree of content.
+
+ const fallback = props.fallback;
+ const content = props.children;
+ const fallbackAbortSet = new Set();
+ const newBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+
+ if (request.trackedPostpones !== null) {
+ newBoundary.trackedContentKeyPath = keyPath;
+ }
+
+ const insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback.
+
+ const boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false);
+ parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent
+
+ parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately.
+
+ const contentRootSegment = createPendingSegment(request, 0, null, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is
+ // no parent segment so there's nothing to wait on.
+
+ contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks.
+ // I suspect that there might be some efficiency benefits from not creating the suspended task
+ // and instead just using the stack if possible.
+ // TODO: Call this directly instead of messing with saving and restoring contexts.
+ // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and which segment
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = newBoundary;
+ task.blockedSegment = contentRootSegment;
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, newBoundary.resources);
+ }
+
+ task.keyPath = keyPath;
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+ pushSegmentFinale(contentRootSegment.chunks, request.renderState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded);
+ contentRootSegment.status = COMPLETED;
+ queueCompletedSegment(newBoundary, contentRootSegment);
+
+ if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
+ newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ contentRootSegment.status = ERRORED;
+ newBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ newBoundary.errorDigest = errorDigest;
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.blockedSegment = parentSegment;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]];
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones !== null) {
+ // We create a detached replay node to track any postpones inside the fallback.
+ const fallbackReplayNode = [fallbackKeyPath[1], fallbackKeyPath[2], [], null];
+ trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
+
+ if (newBoundary.status === POSTPONED) {
+ // This must exist now.
+ const boundaryReplayNode = trackedPostpones.workingMap.get(keyPath);
+ boundaryReplayNode[4] = fallbackReplayNode;
+ } else {
+ // We might not inject it into the postponed tree, unless the content actually
+ // postpones too. We need to keep track of it until that happpens.
+ newBoundary.trackedFallbackNode = fallbackReplayNode;
+ }
+ } // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+
+ const suspendedFallbackTask = createRenderTask(request, null, fallback, -1, parentBoundary, boundarySegment, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function replaySuspenseBoundary(request, task, keyPath, props, id, childNodes, childSlots, fallbackNodes, fallbackSlots) {
+ const prevKeyPath = task.keyPath;
+ const previousReplaySet = task.replay;
+ const parentBoundary = task.blockedBoundary;
+ const content = props.children;
+ const fallback = props.fallback;
+ const fallbackAbortSet = new Set();
+ const resumedBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = id; // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and replay node
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = resumedBoundary;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, resumedBoundary.resources);
+ }
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+
+ if (resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING) {
+ resumedBoundary.status = COMPLETED;
+ request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ resumedBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ resumedBoundary.errorDigest = errorDigest;
+
+ task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted.
+
+ request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task.
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.replay = previousReplaySet;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+ const fallbackReplay = {
+ nodes: fallbackNodes,
+ slots: fallbackSlots,
+ pendingTasks: 0
+ };
+ const suspendedFallbackTask = createReplayTask(request, null, fallbackReplay, fallback, -1, parentBoundary, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function renderHostElement(request, task, keyPath, type, props) {
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ const children = props.children; // TODO: Make this a Config for replaying.
+
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ } else {
+ // Render
+ const children = pushStartInstance(segment.chunks, type, props, request.resumableState, request.renderState, task.formatContext, segment.lastPushedText);
+ segment.lastPushedText = false;
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ pushEndInstance(segment.chunks, type, props, request.resumableState, prevContext);
+ segment.lastPushedText = false;
+ }
+}
+
+function shouldConstruct(Component) {
+ return Component.prototype && Component.prototype.isReactComponent;
+}
+
+function renderWithHooks(request, task, keyPath, prevThenableState, Component, props, secondArg) {
+ const componentIdentity = {};
+ prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState);
+ const result = Component(props, secondArg);
+ return finishHooks(Component, props, result, secondArg);
+}
+
+function finishClassComponent(request, task, keyPath, instance, Component, props) {
+ const nextChildren = instance.render();
+
+ {
+ const childContextTypes = Component.childContextTypes;
+
+ if (childContextTypes !== null && childContextTypes !== undefined) {
+ const previousContext = task.legacyContext;
+ const mergedContext = processChildContext(instance, Component, previousContext, childContextTypes);
+ task.legacyContext = mergedContext;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.legacyContext = previousContext;
+ return;
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderClassComponent(request, task, keyPath, Component, props) {
+ const maskedContext = getMaskedContext(Component, task.legacyContext) ;
+ const instance = constructClassInstance(Component, props, maskedContext);
+ mountClassInstance(instance, Component, props, maskedContext);
+ finishClassComponent(request, task, keyPath, instance, Component);
+}
+// components for some reason.
+
+function renderIndeterminateComponent(request, task, keyPath, prevThenableState, Component, props) {
+ let legacyContext;
+
+ {
+ legacyContext = getMaskedContext(Component, task.legacyContext);
+ }
+
+ const value = renderWithHooks(request, task, keyPath, prevThenableState, Component, props, legacyContext);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+
+ if ( // Run these checks in production only if the flag is off.
+ // Eventually we'll delete this branch altogether.
+ typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
+
+ mountClassInstance(value, Component, props, legacyContext);
+ finishClassComponent(request, task, keyPath, value, Component);
+ } else {
+
+ finishFunctionComponent(request, task, keyPath, value, hasId, formStateCount, formStateMatchingIndex);
+ }
+}
+
+function finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex) {
+ let didEmitFormStateMarkers = false;
+
+ if (formStateCount !== 0 && request.formState !== null) {
+ // For each useFormState hook, emit a marker that indicates whether we
+ // rendered using the form state passed at the root. We only emit these
+ // markers if form state is passed at the root.
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ didEmitFormStateMarkers = true;
+ const target = segment.chunks;
+
+ for (let i = 0; i < formStateCount; i++) {
+ if (i === formStateMatchingIndex) {
+ pushFormStateMarkerIsMatching(target);
+ } else {
+ pushFormStateMarkerIsNotMatching(target);
+ }
+ }
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+
+ if (hasId) {
+ // This component materialized an id. We treat this as its own level, with
+ // a single "child" slot.
+ const prevTreeContext = task.treeContext;
+ const totalChildren = 1;
+ const index = 0; // Modify the id context. Because we'll need to reset this if something
+ // suspends or errors, we'll use the non-destructive render path.
+
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
+ renderNode(request, task, children, -1); // Like the other contexts, this does not need to be in a finally block
+ // because renderNode takes care of unwinding the stack.
+
+ task.treeContext = prevTreeContext;
+ } else if (didEmitFormStateMarkers) {
+ // If there were formState hooks, we must use the non-destructive path
+ // because this component is not a pure indirection; we emitted markers
+ // to the stream.
+ renderNode(request, task, children, -1);
+ } else {
+ // We're now successfully past this task, and we haven't modified the
+ // context stack. We don't have to pop back to the previous task every
+ // again, so we can use the destructive recursive form.
+ renderNodeDestructive(request, task, null, children, -1);
+ }
+
+ task.keyPath = prevKeyPath;
+}
+
+function resolveDefaultProps(Component, baseProps) {
+ if (Component && Component.defaultProps) {
+ // Resolve default props. Taken from ReactElement
+ const props = assign({}, baseProps);
+ const defaultProps = Component.defaultProps;
+
+ for (const propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+
+ return props;
+ }
+
+ return baseProps;
+}
+
+function renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref) {
+ const children = renderWithHooks(request, task, keyPath, prevThenableState, type.render, props, ref);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+ finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex);
+}
+
+function renderMemo(request, task, keyPath, prevThenableState, type, props, ref) {
+ const innerType = type.type;
+ const resolvedProps = resolveDefaultProps(innerType, props);
+ renderElement(request, task, keyPath, prevThenableState, innerType, resolvedProps, ref);
+}
+
+function renderContextConsumer(request, task, keyPath, context, props) {
+
+ const render = props.children;
+
+ const newValue = readContext$1(context);
+ const newChildren = render(newValue);
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, newChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderContextProvider(request, task, keyPath, type, props) {
+ const context = type._context;
+ const value = props.value;
+ const children = props.children;
+
+ const prevKeyPath = task.keyPath;
+ task.context = pushProvider(context, value);
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, children, -1);
+ task.context = popProvider();
+ task.keyPath = prevKeyPath;
+}
+
+function renderLazyComponent(request, task, keyPath, prevThenableState, lazyComponent, props, ref) {
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+ const Component = init(payload);
+ const resolvedProps = resolveDefaultProps(Component, props);
+ renderElement(request, task, keyPath, prevThenableState, Component, resolvedProps, ref);
+}
+
+function renderOffscreen(request, task, keyPath, props) {
+ const mode = props.mode;
+
+ if (mode === 'hidden') ; else {
+ // A visible Offscreen boundary is treated exactly like a fragment: a
+ // pure indirection.
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ }
+}
+
+function renderElement(request, task, keyPath, prevThenableState, type, props, ref) {
+ if (typeof type === 'function') {
+ if (shouldConstruct(type)) {
+ renderClassComponent(request, task, keyPath, type, props);
+ return;
+ } else {
+ renderIndeterminateComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+
+ if (typeof type === 'string') {
+ renderHostElement(request, task, keyPath, type, props);
+ return;
+ }
+
+ switch (type) {
+ // LegacyHidden acts the same as a fragment. This only works because we
+ // currently assume that every instance of LegacyHidden is accompanied by a
+ // host component wrapper. In the hidden mode, the host component is given a
+ // `hidden` attribute, which ensures that the initial HTML is not visible.
+ // To support the use of LegacyHidden as a true fragment, without an extra
+ // DOM node, we would have to hide the initial HTML in some other way.
+ // TODO: Delete in LegacyHidden. It's an unstable API only used in the
+ // www build. As a migration step, we could add a special prop to Offscreen
+ // that simulates the old behavior (no hiding, no change to effects).
+ case REACT_LEGACY_HIDDEN_TYPE:
+ case REACT_DEBUG_TRACING_MODE_TYPE:
+ case REACT_STRICT_MODE_TYPE:
+ case REACT_PROFILER_TYPE:
+ case REACT_FRAGMENT_TYPE:
+ {
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_OFFSCREEN_TYPE:
+ {
+ renderOffscreen(request, task, keyPath, props);
+ return;
+ }
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ {
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_SCOPE_TYPE:
+ {
+
+ throw new Error('ReactDOMServer does not yet support scope components.');
+ }
+
+ case REACT_SUSPENSE_TYPE:
+ {
+ {
+ renderSuspenseBoundary(request, task, keyPath, props);
+ }
+
+ return;
+ }
+ }
+
+ if (typeof type === 'object' && type !== null) {
+ switch (type.$$typeof) {
+ case REACT_FORWARD_REF_TYPE:
+ {
+ renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_MEMO_TYPE:
+ {
+ renderMemo(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_PROVIDER_TYPE:
+ {
+ renderContextProvider(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_CONTEXT_TYPE:
+ {
+ renderContextConsumer(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_LAZY_TYPE:
+ {
+ renderLazyComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+ }
+
+ let info = '';
+
+ throw new Error('Element type is invalid: expected a string (for built-in ' + 'components) or a class/function (for composite components) ' + ("but got: " + (type == null ? type : typeof type) + "." + info));
+}
+
+function resumeNode(request, task, segmentId, node, childIndex) {
+ const prevReplay = task.replay;
+ const blockedBoundary = task.blockedBoundary;
+ const resumedSegment = createPendingSegment(request, 0, null, task.formatContext, false, false);
+ resumedSegment.id = segmentId;
+ resumedSegment.parentFlushed = true;
+
+ try {
+ // Convert the current ReplayTask to a RenderTask.
+ const renderTask = task;
+ renderTask.replay = null;
+ renderTask.blockedSegment = resumedSegment;
+ renderNode(request, task, node, childIndex);
+ resumedSegment.status = COMPLETED;
+
+ if (blockedBoundary === null) {
+ request.completedRootSegment = resumedSegment;
+ } else {
+ queueCompletedSegment(blockedBoundary, resumedSegment);
+
+ if (blockedBoundary.parentFlushed) {
+ request.partialBoundaries.push(blockedBoundary);
+ }
+ }
+ } finally {
+ // Restore to a ReplayTask.
+ task.replay = prevReplay;
+ task.blockedSegment = null;
+ }
+}
+
+function replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, replay) {
+ // We're replaying. Find the path to follow.
+ const replayNodes = replay.nodes;
+
+ for (let i = 0; i < replayNodes.length; i++) {
+ // Flow doesn't support refinement on tuples so we do it manually here.
+ const node = replayNodes[i];
+
+ if (keyOrIndex !== node[1]) {
+ continue;
+ }
+
+ if (node.length === 4) {
+ // Matched a replayable path.
+ // Let's double check that the component name matches as a precaution.
+ if (name !== null && name !== node[0]) {
+ throw new Error('Expected the resume to render <' + node[0] + '> in this slot but instead it rendered <' + name + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ const currentNode = task.node;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0 // TODO check remaining slots
+ ) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ if (task.node === currentNode) {
+ // This same element suspended so we need to pop the replay we just added.
+ task.replay = replay;
+ }
+
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay;
+ } else {
+ // Let's double check that the component type matches.
+ if (type !== REACT_SUSPENSE_TYPE) {
+ const expectedType = 'Suspense';
+ throw new Error('Expected the resume to render <' + expectedType + '> in this slot but instead it rendered <' + (getComponentNameFromType(type) || 'Unknown') + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ } // Matched a replayable path.
+
+
+ replaySuspenseBoundary(request, task, keyPath, props, node[5], node[2], node[3], node[4] === null ? [] : node[4][2], node[4] === null ? null : node[4][3]);
+ } // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+
+ replayNodes.splice(i, 1);
+ return;
+ } // We didn't find any matching nodes. We assume that this element was already
+ // rendered in the prelude and skip it.
+
+} // $FlowFixMe[missing-local-annot]
+
+function renderNodeDestructive(request, task, // The thenable state reused from the previous attempt, if any. This is almost
+// always null, except when called by retryTask.
+prevThenableState, node, childIndex) {
+ {
+ return renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex);
+ }
+} // This function by it self renders a node and consumes the task by mutating it
+// to update the current execution state.
+
+
+function renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex) {
+ if (task.replay !== null && typeof task.replay.slots === 'number') {
+ // TODO: Figure out a cheaper place than this hot path to do this check.
+ const resumeSegmentID = task.replay.slots;
+ resumeNode(request, task, resumeSegmentID, node, childIndex);
+ return;
+ } // Stash the node we're working on. We'll pick up from this task in case
+ // something suspends.
+
+
+ task.node = node;
+ task.childIndex = childIndex; // Handle object types
+
+ if (typeof node === 'object' && node !== null) {
+ switch (node.$$typeof) {
+ case REACT_ELEMENT_TYPE:
+ {
+ const element = node;
+ const type = element.type;
+ const key = element.key;
+ const props = element.props;
+ const ref = element.ref;
+ const name = getComponentNameFromType(type);
+ const keyOrIndex = key == null ? childIndex === -1 ? 0 : childIndex : key;
+ const keyPath = [task.keyPath, name, keyOrIndex];
+
+ if (task.replay !== null) {
+ replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, task.replay); // No matches found for this node. We assume it's already emitted in the
+ // prelude and skip it during the replay.
+ } else {
+ // We're doing a plain render.
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+ }
+
+ return;
+ }
+
+ case REACT_PORTAL_TYPE:
+ throw new Error('Portals are not currently supported by the server renderer. ' + 'Render them conditionally so that they only appear on the client render.');
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyNode = node;
+ const payload = lazyNode._payload;
+ const init = lazyNode._init;
+ let resolvedNode;
+
+ {
+ resolvedNode = init(payload);
+ }
+
+ renderNodeDestructive(request, task, null, resolvedNode, childIndex);
+ return;
+ }
+ }
+
+ if (isArray(node)) {
+ renderChildrenArray(request, task, node, childIndex);
+ return;
+ }
+
+ const iteratorFn = getIteratorFn(node);
+
+ if (iteratorFn) {
+
+ const iterator = iteratorFn.call(node);
+
+ if (iterator) {
+ // We need to know how many total children are in this set, so that we
+ // can allocate enough id slots to acommodate them. So we must exhaust
+ // the iterator before we start recursively rendering the children.
+ // TODO: This is not great but I think it's inherent to the id
+ // generation algorithm.
+ let step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that.
+
+ if (!step.done) {
+ const children = [];
+
+ do {
+ children.push(step.value);
+ step = iterator.next();
+ } while (!step.done);
+
+ renderChildrenArray(request, task, children, childIndex);
+ return;
+ }
+
+ return;
+ }
+ } // Usables are a valid React node type. When React encounters a Usable in
+ // a child position, it unwraps it using the same algorithm as `use`. For
+ // example, for promises, React will throw an exception to unwind the
+ // stack, then replay the component once the promise resolves.
+ //
+ // A difference from `use` is that React will keep unwrapping the value
+ // until it reaches a non-Usable type.
+ //
+ // e.g. Usable>> should resolve to T
+
+
+ const maybeUsable = node;
+
+ if (typeof maybeUsable.then === 'function') {
+ const thenable = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable), childIndex);
+ }
+
+ if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, readContext$1(context), childIndex);
+ } // $FlowFixMe[method-unbinding]
+
+
+ const childString = Object.prototype.toString.call(node);
+ throw new Error("Objects are not valid as a React child (found: " + (childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString) + "). " + 'If you meant to render a collection of children, use an array ' + 'instead.');
+ }
+
+ if (typeof node === 'string') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+
+ if (typeof node === 'number') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, '' + node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+}
+
+function replayFragment(request, task, children, childIndex) {
+ // If we're supposed follow this array, we'd expect to see a ReplayNode matching
+ // this fragment.
+ const replay = task.replay;
+ const replayNodes = replay.nodes;
+
+ for (let j = 0; j < replayNodes.length; j++) {
+ const node = replayNodes[j];
+
+ if (node[1] !== childIndex) {
+ continue;
+ } // Matched a replayable path.
+
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderChildrenArray(request, task, children, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+ // This is an error, stash the component stack if it is null.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay; // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ replayNodes.splice(j, 1);
+ break;
+ }
+}
+
+function renderChildrenArray(request, task, children, childIndex) {
+ const prevKeyPath = task.keyPath;
+
+ if (childIndex !== -1) {
+ task.keyPath = [task.keyPath, 'Fragment', childIndex];
+
+ if (task.replay !== null) {
+ replayFragment(request, // $FlowFixMe: Refined.
+ task, children, childIndex);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ const prevTreeContext = task.treeContext;
+ const totalChildren = children.length;
+
+ if (task.replay !== null) {
+ // Replay
+ // First we need to check if we have any resume slots at this level.
+ const resumeSlots = task.replay.slots;
+
+ if (resumeSlots !== null && typeof resumeSlots === 'object') {
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ const resumeSegmentID = resumeSlots[i]; // TODO: If this errors we should still continue with the next sibling.
+
+ if (typeof resumeSegmentID === 'number') {
+ resumeNode(request, task, resumeSegmentID, node, i); // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ delete resumeSlots[i];
+ } else {
+ renderNode(request, task, node, i);
+ }
+ }
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ renderNode(request, task, node, i);
+ } // Because this context is always set right before rendering every child, we
+ // only need to reset it to the previous value at the very end.
+
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+}
+
+function spawnNewSuspendedReplayTask(request, task, thenableState, x) {
+ const newTask = createReplayTask(request, thenableState, task.replay, task.node, task.childIndex, task.blockedBoundary, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+}
+
+function spawnNewSuspendedRenderTask(request, task, thenableState, x) {
+ // Something suspended, we'll need to create a new segment and resolve it later.
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ const newTask = createRenderTask(request, thenableState, task.node, task.childIndex, task.blockedBoundary, newSegment, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+} // This is a non-destructive form of rendering a node. If it suspends it spawns
+// a new task and restores the context of this task to what it was before.
+
+
+function renderNode(request, task, node, childIndex) {
+ // Snapshot the current context in case something throws to interrupt the
+ // process.
+ const previousFormatContext = task.formatContext;
+ const previousLegacyContext = task.legacyContext;
+ const previousContext = task.context;
+ const previousKeyPath = task.keyPath;
+ const previousTreeContext = task.treeContext;
+
+ let x; // Store how much we've pushed at this point so we can reset it in case something
+ // suspended partially through writing something.
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState();
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedReplayTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode.
+
+ }
+ } else {
+ // Render
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedRenderTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ }
+ }
+ } // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ // Let's terminate the rest of the tree and don't render any siblings.
+
+
+ throw x;
+}
+
+function erroredReplay(request, boundary, error, replayNodes, resumeSlots) {
+ // Erroring during a replay doesn't actually cause an error by itself because
+ // that component has already rendered. What causes the error is the resumable
+ // points that we did not yet finish which will be below the point of the reset.
+ // For example, if we're replaying a path to a Suspense boundary that is not done
+ // that doesn't error the parent Suspense boundary.
+ // This might be a bit strange that the error in a parent gets thrown at a child.
+ // We log it only once and reuse the digest.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ abortRemainingReplayNodes(request, boundary, replayNodes, resumeSlots, error, errorDigest);
+}
+
+function erroredTask(request, boundary, error) {
+ // Report the error to a global handler.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ if (boundary === null) {
+ fatalError(request, error);
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+ // so we can flush it, if the parent already flushed.
+
+
+ if (boundary.parentFlushed) {
+ // We don't have a preference where in the queue this goes since it's likely
+ // to error on the client anyway. However, intentionally client-rendered
+ // boundaries should be flushed earlier so that they can start on the client.
+ // We reuse the same queue for errors.
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function abortTaskSoft(task) {
+ // This aborts task without aborting the parent boundary that it blocks.
+ // It's used for when we didn't need this task to complete the tree.
+ // If task was needed, then it should use abortTask instead.
+ const request = this;
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ finishedTask(request, boundary, segment);
+ }
+}
+
+function abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest) {
+ const resumedBoundary = createSuspenseBoundary(request, new Set());
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = rootSegmentID;
+ resumedBoundary.status = CLIENT_RENDERED;
+ resumedBoundary.errorDigest = errorDigest;
+
+ if (resumedBoundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(resumedBoundary);
+ }
+}
+
+function abortRemainingReplayNodes(request, boundary, nodes, slots, error, errorDigest) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+
+ if (node.length === 4) {
+ abortRemainingReplayNodes(request, boundary, node[2], node[3], error, errorDigest);
+ } else {
+ const boundaryNode = node;
+ const rootSegmentID = boundaryNode[5];
+ abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest);
+ }
+ } // Empty the set, since we've cleared it now.
+
+
+ nodes.length = 0;
+
+ if (slots !== null) {
+ // We had something still to resume in the parent boundary. We must trigger
+ // the error on the parent boundary since it's not able to complete.
+ if (boundary === null) {
+ throw new Error('We should not have any resumable nodes in the shell. ' + 'This is a bug in React.');
+ } else if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // Empty the set
+
+
+ if (typeof slots === 'object') {
+ for (const index in slots) {
+ delete slots[index];
+ }
+ }
+ }
+}
+
+function abortTask(task, request, error) {
+ // This aborts the task and aborts the parent that it blocks, putting it into
+ // client rendered mode.
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ }
+
+ if (boundary === null) {
+ if (request.status !== CLOSING && request.status !== CLOSED) {
+ const replay = task.replay;
+
+ if (replay === null) {
+ // We didn't complete the root so we have nothing to show. We can close
+ // the request;
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ return;
+ } else {
+ // If the shell aborts during a replay, that's not a fatal error. Instead
+ // we should be able to recover by client rendering all the root boundaries in
+ // the ReplaySet.
+ replay.pendingTasks--;
+
+ if (replay.pendingTasks === 0 && replay.nodes.length > 0) {
+ const errorDigest = logRecoverableError(request, error);
+ abortRemainingReplayNodes(request, null, replay.nodes, replay.slots, error, errorDigest);
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ }
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = logRecoverableError(request, error);
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // If this boundary was still pending then we haven't already cancelled its fallbacks.
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
+
+
+ boundary.fallbackAbortableTasks.forEach(fallbackTask => abortTask(fallbackTask, request, error));
+ boundary.fallbackAbortableTasks.clear();
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeShell(request) {
+ if (request.trackedPostpones === null) {
+ // We only emit early preloads on shell completion for renders. For prerenders
+ // we wait for the entire Request to finish because we are not responding to a
+ // live request and can wait for as much data as possible.
+ // we should only be calling completeShell when the shell is complete so we
+ // just use a literal here
+ const shellComplete = true;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ } // We have completed the shell so the shell can't error anymore.
+
+
+ request.onShellError = noop;
+ const onShellReady = request.onShellReady;
+ onShellReady();
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeAll(request) {
+ // During a render the shell must be complete if the entire request is finished
+ // however during a Prerender it is possible that the shell is incomplete because
+ // it postponed. We cannot use rootPendingTasks in the prerender case because
+ // those hit zero even when the shell postpones. Instead we look at the completedRootSegment
+ const shellComplete = request.trackedPostpones === null ? // Render, we assume it is completed
+ true : // Prerender Request, we use the state of the root segment
+ request.completedRootSegment === null || request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ const onAllReady = request.onAllReady;
+ onAllReady();
+}
+
+function queueCompletedSegment(boundary, segment) {
+ if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) {
+ // This is an empty segment. There's nothing to write, so we can instead transfer the ID
+ // to the child. That way any existing references point to the child.
+ const childSegment = segment.children[0];
+ childSegment.id = segment.id;
+ childSegment.parentFlushed = true;
+
+ if (childSegment.status === COMPLETED) {
+ queueCompletedSegment(boundary, childSegment);
+ }
+ } else {
+ const completedSegments = boundary.completedSegments;
+ completedSegments.push(segment);
+ }
+}
+
+function finishedTask(request, boundary, segment) {
+ if (boundary === null) {
+ if (segment !== null && segment.parentFlushed) {
+ if (request.completedRootSegment !== null) {
+ throw new Error('There can only be one root segment. This is a bug in React.');
+ }
+
+ request.completedRootSegment = segment;
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status === CLIENT_RENDERED) ; else if (boundary.pendingTasks === 0) {
+ if (boundary.status === PENDING) {
+ boundary.status = COMPLETED;
+ } // This must have been the last segment we were waiting on. This boundary is now complete.
+
+
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent segment already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ }
+ }
+
+ if (boundary.parentFlushed) {
+ // The segment might be part of a segment that didn't flush yet, but if the boundary's
+ // parent flushed, we need to schedule the boundary to be emitted.
+ request.completedBoundaries.push(boundary);
+ } // We can now cancel any pending task on the fallback since we won't need to show it anymore.
+ // This needs to happen after we read the parentFlushed flags because aborting can finish
+ // work which can trigger user code, which can start flushing, which can change those flags.
+ // If the boundary was POSTPONED, we still need to finish the fallback first.
+
+
+ if (boundary.status === COMPLETED) {
+ boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
+ boundary.fallbackAbortableTasks.clear();
+ }
+ } else {
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length === 1) {
+ // This is the first time since we last flushed that we completed anything.
+ // We can schedule this boundary to emit its partially completed segments early
+ // in case the parent has already been flushed.
+ if (boundary.parentFlushed) {
+ request.partialBoundaries.push(boundary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function retryTask(request, task) {
+ {
+ const blockedBoundary = task.blockedBoundary;
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, blockedBoundary ? blockedBoundary.resources : null);
+ }
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ retryReplayTask(request, // $FlowFixMe: Refined.
+ task);
+ } else {
+ retryRenderTask(request, // $FlowFixMe: Refined.
+ task, segment);
+ }
+}
+
+function retryRenderTask(request, task, segment) {
+ if (segment.status !== PENDING) {
+ // We completed this by other means before we had a chance to retry it.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+ pushSegmentFinale(segment.chunks, request.renderState, segment.lastPushedText, segment.textEmbedded);
+ task.abortSet.delete(task);
+ segment.status = COMPLETED;
+ finishedTask(request, task.blockedBoundary, segment);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.abortSet.delete(task);
+ segment.status = ERRORED;
+ erroredTask(request, task.blockedBoundary, x);
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function retryReplayTask(request, task) {
+ if (task.replay.pendingTasks === 0) {
+ // There are no pending tasks working on this set, so we must have aborted.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ finishedTask(request, task.blockedBoundary, null);
+ } catch (thrownValue) {
+ resetHooksState();
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ erroredReplay(request, task.blockedBoundary, x, task.replay.nodes, task.replay.slots);
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function performWork(request) {
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ const prevContext = getActiveContext();
+ const prevDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = HooksDispatcher;
+ let prevCacheDispatcher;
+
+ {
+ prevCacheDispatcher = ReactCurrentCache.current;
+ ReactCurrentCache.current = DefaultCacheDispatcher;
+ }
+
+ const prevRequest = currentRequest;
+ currentRequest = request;
+
+ const prevResumableState = currentResumableState;
+ setCurrentResumableState(request.resumableState);
+
+ try {
+ const pingedTasks = request.pingedTasks;
+ let i;
+
+ for (i = 0; i < pingedTasks.length; i++) {
+ const task = pingedTasks[i];
+ retryTask(request, task);
+ }
+
+ pingedTasks.splice(0, i);
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ } finally {
+ setCurrentResumableState(prevResumableState);
+ ReactCurrentDispatcher.current = prevDispatcher;
+
+ {
+ ReactCurrentCache.current = prevCacheDispatcher;
+ }
+
+ if (prevDispatcher === HooksDispatcher) {
+ // This means that we were in a reentrant work loop. This could happen
+ // in a renderer that supports synchronous work like renderToString,
+ // when it's called from within another renderer.
+ // Normally we don't bother switching the contexts to their root/default
+ // values when leaving because we'll likely need the same or similar
+ // context again. However, when we're inside a synchronous loop like this
+ // we'll to restore the context to what it was before returning.
+ switchContext(prevContext);
+ }
+
+ currentRequest = prevRequest;
+ }
+}
+
+function flushSubtree(request, destination, segment) {
+ segment.parentFlushed = true;
+
+ switch (segment.status) {
+ case PENDING:
+ {
+ // We're emitting a placeholder for this segment to be filled in later.
+ // Therefore we'll need to assign it an ID - to refer to it by.
+ segment.id = request.nextSegmentId++; // Fallthrough
+ }
+
+ case POSTPONED:
+ {
+ const segmentID = segment.id; // When this segment finally completes it won't be embedded in text since it will flush separately
+
+ segment.lastPushedText = false;
+ segment.textEmbedded = false;
+ return writePlaceholder(destination, request.renderState, segmentID);
+ }
+
+ case COMPLETED:
+ {
+ segment.status = FLUSHED;
+ let r = true;
+ const chunks = segment.chunks;
+ let chunkIdx = 0;
+ const children = segment.children;
+
+ for (let childIdx = 0; childIdx < children.length; childIdx++) {
+ const nextChild = children[childIdx]; // Write all the chunks up until the next child.
+
+ for (; chunkIdx < nextChild.index; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ r = flushSegment(request, destination, nextChild);
+ } // Finally just write all the remaining chunks
+
+
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ if (chunkIdx < chunks.length) {
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
+ }
+
+ return r;
+ }
+
+ default:
+ {
+ throw new Error('Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.');
+ }
+ }
+}
+
+function flushSegment(request, destination, segment) {
+ const boundary = segment.boundary;
+
+ if (boundary === null) {
+ // Not a suspense boundary.
+ return flushSubtree(request, destination, segment);
+ }
+
+ boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to
+ // emit the content or the fallback now.
+
+ if (boundary.status === CLIENT_RENDERED) {
+ // Emit a client rendered suspense boundary wrapper.
+ // We never queue the inner boundary so we'll never emit its content or partial segments.
+ writeStartClientRenderedSuspenseBoundary(destination, request.renderState, boundary.errorDigest); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndClientRenderedSuspenseBoundary(destination);
+ } else if (boundary.status !== COMPLETED) {
+ if (boundary.status === PENDING) {
+ // For pending boundaries we lazily assign an ID to the boundary
+ // and root segment.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ }
+
+ if (boundary.completedSegments.length > 0) {
+ // If this is at least partially complete, we can queue it to be partially emitted early.
+ request.partialBoundaries.push(boundary);
+ } // This boundary is still loading. Emit a pending suspense boundary wrapper.
+
+
+ const id = boundary.rootSegmentID;
+ writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else if (boundary.byteSize > request.progressiveChunkSize) {
+ // This boundary is large and will be emitted separately so that we can progressively show
+ // other content. We add it to the queue during the flush because we have to ensure that
+ // the parent flushes first so that there's something to inject it into.
+ // We also have to make sure that it's emitted into the queue in a deterministic slot.
+ // I.e. we can't insert it here when it completes.
+ // Assign an ID to refer to the future content by.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper.
+
+ writeStartPendingSuspenseBoundary(destination, request.renderState, boundary.rootSegmentID); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else {
+ {
+ hoistResources(request.renderState, boundary.resources);
+ } // We can inline this boundary's content as a complete boundary.
+
+
+ writeStartCompletedSuspenseBoundary(destination);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length !== 1) {
+ throw new Error('A previously unvisited boundary must have exactly one root segment. This is a bug in React.');
+ }
+
+ const contentSegment = completedSegments[0];
+ flushSegment(request, destination, contentSegment);
+ return writeEndCompletedSuspenseBoundary(destination);
+ }
+}
+
+function flushClientRenderedBoundary(request, destination, boundary) {
+ return writeClientRenderBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack);
+}
+
+function flushSegmentContainer(request, destination, segment) {
+ writeStartSegment(destination, request.renderState, segment.parentFormatContext, segment.id);
+ flushSegment(request, destination, segment);
+ return writeEndSegment(destination, segment.parentFormatContext);
+}
+
+function flushCompletedBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+ flushPartiallyCompletedSegment(request, destination, boundary, segment);
+ }
+
+ completedSegments.length = 0;
+
+ {
+ writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+
+ return writeCompletedBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.resources);
+}
+
+function flushPartialBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+
+ if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) {
+ i++;
+ completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority
+ // might want to write later.
+
+ return false;
+ }
+ }
+
+ completedSegments.splice(0, i);
+
+ {
+ // The way this is structured we only write resources for partial boundaries
+ // if there is no backpressure. Later before we complete the boundary we
+ // will write resources regardless of backpressure before we emit the
+ // completion instruction
+ return writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+}
+
+function flushPartiallyCompletedSegment(request, destination, boundary, segment) {
+ if (segment.status === FLUSHED) {
+ // We've already flushed this inline.
+ return true;
+ }
+
+ const segmentID = segment.id;
+
+ if (segmentID === -1) {
+ // This segment wasn't previously referred to. This happens at the root of
+ // a boundary. We make kind of a leap here and assume this is the root.
+ const rootSegmentID = segment.id = boundary.rootSegmentID;
+
+ if (rootSegmentID === -1) {
+ throw new Error('A root segment ID must have been assigned by now. This is a bug in React.');
+ }
+
+ return flushSegmentContainer(request, destination, segment);
+ } else if (segmentID === boundary.rootSegmentID) {
+ // When we emit postponed boundaries, we might have assigned the ID already
+ // but it's still the root segment so we can't inject it into the parent yet.
+ return flushSegmentContainer(request, destination, segment);
+ } else {
+ flushSegmentContainer(request, destination, segment);
+ return writeCompletedSegmentInstruction(destination, request.resumableState, request.renderState, segmentID);
+ }
+}
+
+function flushCompletedQueues(request, destination) {
+
+ try {
+ // The structure of this is to go through each queue one by one and write
+ // until the sink tells us to stop. When we should stop, we still finish writing
+ // that item fully and then yield. At that point we remove the already completed
+ // items up until the point we completed them.
+ let i;
+ const completedRootSegment = request.completedRootSegment;
+
+ if (completedRootSegment !== null) {
+ if (completedRootSegment.status === POSTPONED) {
+ // We postponed the root, so we write nothing.
+ return;
+ } else if (request.pendingRootTasks === 0) {
+ if (enableFloat) {
+ writePreamble(destination, request.resumableState, request.renderState, request.allPendingTasks === 0 && request.trackedPostpones === null);
+ }
+
+ flushSegment(request, destination, completedRootSegment);
+ request.completedRootSegment = null;
+ writeCompletedRoot(destination, request.renderState, request.resumableState);
+ } else {
+ // We haven't flushed the root yet so we don't need to check any other branches further down
+ return;
+ }
+ }
+
+ if (enableFloat) {
+ writeHoistables(destination, request.resumableState, request.renderState);
+ } // We emit client rendering instructions for already emitted boundaries first.
+ // This is so that we can signal to the client to start client rendering them as
+ // soon as possible.
+
+
+ const clientRenderedBoundaries = request.clientRenderedBoundaries;
+
+ for (i = 0; i < clientRenderedBoundaries.length; i++) {
+ const boundary = clientRenderedBoundaries[i];
+
+ if (!flushClientRenderedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ clientRenderedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries
+ // that are completely done since we can actually show them, than it is to emit
+ // any individual segments from a partially complete boundary.
+
+ const completedBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < completedBoundaries.length; i++) {
+ const boundary = completedBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ completedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before
+ // we continue with lower priorities.
+
+ completeWriting(destination);
+ beginWriting(destination); // TODO: Here we'll emit data used by hydration.
+ // Next we emit any segments of any boundaries that are partially complete
+ // but not deeply complete.
+
+ const partialBoundaries = request.partialBoundaries;
+
+ for (i = 0; i < partialBoundaries.length; i++) {
+ const boundary = partialBoundaries[i];
+
+ if (!flushPartialBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ partialBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had
+ // boundaries added to it in case they were too larged to be inlined.
+ // New ones might be added in this loop.
+
+ const largeBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < largeBoundaries.length; i++) {
+ const boundary = largeBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ largeBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ largeBoundaries.splice(0, i);
+ } finally {
+ if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because
+ // either they have pending task or they're complete.
+ ) {
+ request.flushScheduled = false;
+
+ {
+ // We write the trailing tags but only if don't have any data to resume.
+ // If we need to resume we'll write the postamble in the resume instead.
+ {
+ writePostamble(destination, request.resumableState);
+ }
+ }
+
+
+ close(destination); // We need to stop flowing now because we do not want any async contexts which might call
+ // float methods to initiate any flushes after this point
+
+ stopFlowing(request);
+ }
+ }
+}
+
+function startWork(request) {
+ request.flushScheduled = request.destination !== null;
+
+ {
+ scheduleWork(() => performWork(request));
+ }
+
+ if (request.trackedPostpones === null) {
+ // this is either a regular render or a resume. For regular render we want
+ // to call emitEarlyPreloads after the first performWork because we want
+ // are responding to a live request and need to balance sending something early
+ // (i.e. don't want for the shell to finish) but we need something to send.
+ // The only implementation of this is for DOM at the moment and during resumes nothing
+ // actually emits but the code paths here are the same.
+ // During a prerender we don't want to be too aggressive in emitting early preloads
+ // because we aren't responding to a live request and we can wait for the prerender to
+ // postpone before we emit anything.
+ {
+ scheduleWork(() => enqueueEarlyPreloadsAfterInitialWork(request));
+ }
+ }
+}
+
+function enqueueEarlyPreloadsAfterInitialWork(request) {
+ const shellComplete = request.pendingRootTasks === 0;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+
+function enqueueFlush(request) {
+ if (request.flushScheduled === false && // If there are pinged tasks we are going to flush anyway after work completes
+ request.pingedTasks.length === 0 && // If there is no destination there is nothing we can flush to. A flush will
+ // happen when we start flowing again
+ request.destination !== null) {
+ request.flushScheduled = true;
+ scheduleWork(() => {
+ // We need to existence check destination again here because it might go away
+ // in between the enqueueFlush call and the work execution
+ const destination = request.destination;
+
+ if (destination) {
+ flushCompletedQueues(request, destination);
+ } else {
+ request.flushScheduled = false;
+ }
+ });
+ }
+} // This function is intented to only be called during the pipe function for the Node builds.
+function startFlowing(request, destination) {
+ if (request.status === CLOSING) {
+ request.status = CLOSED;
+ closeWithError(destination, request.fatalError);
+ return;
+ }
+
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ if (request.destination !== null) {
+ // We're already flowing.
+ return;
+ }
+
+ request.destination = destination;
+
+ try {
+ flushCompletedQueues(request, destination);
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function stopFlowing(request) {
+ request.destination = null;
+} // This is called to early terminate a request. It puts all pending boundaries in client rendered state.
+
+function abort(request, reason) {
+ try {
+ const abortableTasks = request.abortableTasks;
+
+ if (abortableTasks.size > 0) {
+ const error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason;
+ abortableTasks.forEach(task => abortTask(task, request, error));
+ abortableTasks.clear();
+ }
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function flushResources(request) {
+ enqueueFlush(request);
+}
+function getFormState(request) {
+ return request.formState;
+}
+function getResumableState(request) {
+ return request.resumableState;
+}
+function getRenderState(request) {
+ return request.renderState;
+}
+
+function renderToReadableStream(children, options) {
+ return new Promise((resolve, reject) => {
+ let onFatalError;
+ let onAllReady;
+ const allReady = new Promise((res, rej) => {
+ onAllReady = res;
+ onFatalError = rej;
+ });
+
+ function onShellReady() {
+ const stream = new ReadableStream({
+ type: 'direct',
+ pull: controller => {
+ // $FlowIgnore
+ startFlowing(request, controller);
+ },
+ cancel: reason => {
+ stopFlowing(request);
+ abort(request, reason);
+ }
+ }, // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
+ {
+ highWaterMark: 2048
+ }); // TODO: Move to sub-classing ReadableStream.
+
+ stream.allReady = allReady;
+ resolve(stream);
+ }
+
+ function onShellError(error) {
+ // If the shell errors the caller of `renderToReadableStream` won't have access to `allReady`.
+ // However, `allReady` will be rejected by `onFatalError` as well.
+ // So we need to catch the duplicate, uncatchable fatal error in `allReady` to prevent a `UnhandledPromiseRejection`.
+ allReady.catch(() => {});
+ reject(error);
+ }
+
+ const onHeaders = options ? options.onHeaders : undefined;
+ let onHeadersImpl;
+
+ if (onHeaders) {
+ onHeadersImpl = headersDescriptor => {
+ onHeaders(new Headers(headersDescriptor));
+ };
+ }
+
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ const request = createRequest(children, resumableState, createRenderState(resumableState, options ? options.nonce : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, onHeadersImpl, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, onAllReady, onShellReady, onShellError, onFatalError, options ? options.onPostpone : undefined, options ? options.formState : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+function renderToNodeStream() {
+ throw new Error('ReactDOMServer.renderToNodeStream(): The Node Stream API is not available ' + 'in Bun. Use ReactDOMServer.renderToReadableStream() instead.');
+}
+
+function renderToStaticNodeStream() {
+ throw new Error('ReactDOMServer.renderToStaticNodeStream(): The Node Stream API is not available ' + 'in Bun. Use ReactDOMServer.renderToReadableStream() instead.');
+}
+
+exports.renderToNodeStream = renderToNodeStream;
+exports.renderToReadableStream = renderToReadableStream;
+exports.renderToStaticNodeStream = renderToStaticNodeStream;
+exports.version = ReactVersion;
\ No newline at end of file
diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js
index ce56f4c3238b5..6704296583e2b 100644
--- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js
+++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js
@@ -17,7 +17,7 @@ if (process.env.NODE_ENV !== "production") {
var React = require("next/dist/compiled/react");
var ReactDOM = require('react-dom');
-var ReactVersion = '18.3.0-canary-2983249dd-20231107';
+var ReactVersion = '18.3.0-canary-7508dcd5c-20231108';
var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
@@ -1809,11 +1809,14 @@ var DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep tr
// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
// is set, the server will send instructions via data attributes (instead of inline scripts)
-function createRenderState(resumableState, nonce, bootstrapScriptContent, bootstrapScripts, bootstrapModules, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+function createRenderState(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
var inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const startScriptSrc = stringToPrecomputedChunk('');
+/**
+ * This escaping function is designed to work with bootstrapScriptContent and importMap only.
+ * because we know we are escaping the entire script. We can avoid for instance
+ * escaping html comment string sequences that are valid javascript as well because
+ * if there are no sebsequent '); // Since we store headers as strings we deal with their length in utf16 code units
+// rather than visual characters or the utf8 encoding that is used for most binary
+// serialization. Some common HTTP servers only allow for headers to be 4kB in length.
+// We choose a default length that is likely to be well under this already limited length however
+// pathological cases may still cause the utf-8 encoding of the headers to approach this limit.
+// It should also be noted that this maximum is a soft maximum. we have not reached the limit we will
+// allow one more header to be captured which means in practice if the limit is approached it will be exceeded
+
+const DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep track of what we've already written so we can refer back to it.
+// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
+// is set, the server will send instructions via data attributes (instead of inline scripts)
+
+function createRenderState(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+ const inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const completeSegmentData1 = stringToPrecomputedChunk('');
+const completeBoundaryData1 = stringToPrecomputedChunk('');
+const clientRenderData1 = stringToPrecomputedChunk('
+ return writeChunkAndReturn(destination, clientRenderDataEnd);
+ }
+}
+const regexForJSStringsInInstructionScripts = /[<\u2028\u2029]/g;
+
+function escapeJSStringsForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInInstructionScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const regexForJSStringsInScripts = /[&><\u2028\u2029]/g;
+
+function escapeJSObjectForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '&':
+ return '\\u0026';
+
+ case '>':
+ return '\\u003e';
+
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(''); // Tracks whether the boundary currently flushing is flushign style tags or has any
+// stylesheet dependencies not flushed in the Preamble.
+
+let currentlyRenderingBoundaryHasStylesToHoist = false; // Acts as a return value for the forEach execution of style tag flushing.
+
+let destinationHasCapacity = true;
+
+function flushStyleTagsLateForBoundary(styleQueue) {
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs;
+
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, lateStyleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ writeChunk(this, lateStyleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, lateStyleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ destinationHasCapacity = writeChunkAndReturn(this, lateStyleTagTemplateClose); // We wrote style tags for this boundary and we may need to emit a script
+ // to hoist them.
+
+ currentlyRenderingBoundaryHasStylesToHoist = true; // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function hasStylesToHoist(stylesheet) {
+ // We need to reveal boundaries with styles whenever a stylesheet it depends on is either
+ // not flushed or flushed after the preamble (shell).
+ if (stylesheet.state !== PREAMBLE) {
+ currentlyRenderingBoundaryHasStylesToHoist = true;
+ return true;
+ }
+
+ return false;
+}
+
+function writeResourcesForBoundary(destination, boundaryResources, renderState) {
+ // Reset these on each invocation, they are only safe to read in this function
+ currentlyRenderingBoundaryHasStylesToHoist = false;
+ destinationHasCapacity = true; // Flush style tags for each precedence this boundary depends on
+
+ boundaryResources.styles.forEach(flushStyleTagsLateForBoundary, destination); // Determine if this boundary has stylesheets that need to be awaited upon completion
+
+ boundaryResources.stylesheets.forEach(hasStylesToHoist);
+
+ if (currentlyRenderingBoundaryHasStylesToHoist) {
+ renderState.stylesToHoist = true;
+ }
+
+ return destinationHasCapacity;
+}
+
+function flushResource(resource) {
+ for (let i = 0; i < resource.length; i++) {
+ writeChunk(this, resource[i]);
+ }
+
+ resource.length = 0;
+}
+
+const stylesheetFlushingQueue = [];
+
+function flushStyleInPreamble(stylesheet, key, map) {
+ // We still need to encode stylesheet chunks
+ // because unlike most Hoistables and Resources we do not eagerly encode
+ // them during render. This is because if we flush late we have to send a
+ // different encoding and we don't want to encode multiple times
+ pushLinkImpl(stylesheetFlushingQueue, stylesheet.props);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ stylesheet.state = PREAMBLE;
+}
+
+const styleTagResourceOpen1 = stringToPrecomputedChunk('');
+
+function flushStylesInPreamble(styleQueue, precedence) {
+ const hasStylesheets = styleQueue.sheets.size > 0;
+ styleQueue.sheets.forEach(flushStyleInPreamble, this);
+ styleQueue.sheets.clear();
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs; // If we don't emit any stylesheets at this precedence we still need to maintain the precedence
+ // order so even if there are no rules for style tags at this precedence we emit an empty style
+ // tag with the data-precedence attribute
+
+ if (!hasStylesheets || hrefs.length) {
+ writeChunk(this, styleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, styleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ }
+
+ writeChunk(this, styleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ writeChunk(this, styleTagResourceClose); // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function preloadLateStyle(stylesheet) {
+ if (stylesheet.state === PENDING$1) {
+ stylesheet.state = PRELOADED;
+ const preloadProps = preloadAsStylePropsFromProps(stylesheet.props.href, stylesheet.props);
+ pushLinkImpl(stylesheetFlushingQueue, preloadProps);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ }
+}
+
+function preloadLateStyles(styleQueue) {
+ styleQueue.sheets.forEach(preloadLateStyle, this);
+ styleQueue.sheets.clear();
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+
+function writePreamble(destination, resumableState, renderState, willFlushAllSegments) {
+ // This function must be called exactly once on every request
+ if (!willFlushAllSegments && renderState.externalRuntimeScript) {
+ // If the root segment is incomplete due to suspended tasks
+ // (e.g. willFlushAllSegments = false) and we are using data
+ // streaming format, ensure the external runtime is sent.
+ // (User code could choose to send this even earlier by calling
+ // preinit(...), if they know they will suspend).
+ const _renderState$external = renderState.externalRuntimeScript,
+ src = _renderState$external.src,
+ chunks = _renderState$external.chunks;
+ internalPreinitScript(resumableState, renderState, src, chunks);
+ }
+
+ const htmlChunks = renderState.htmlChunks;
+ const headChunks = renderState.headChunks;
+ let i = 0; // Emit open tags before Hoistables and Resources
+
+ if (htmlChunks) {
+ // We have an to emit as part of the preamble
+ for (i = 0; i < htmlChunks.length; i++) {
+ writeChunk(destination, htmlChunks[i]);
+ }
+
+ if (headChunks) {
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } else {
+ // We did not render a head but we emitted an so we emit one now
+ writeChunk(destination, startChunkForTag('head'));
+ writeChunk(destination, endOfStartTag);
+ }
+ } else if (headChunks) {
+ // We do not have an but we do have a
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } // Emit high priority Hoistables
+
+
+ const charsetChunks = renderState.charsetChunks;
+
+ for (i = 0; i < charsetChunks.length; i++) {
+ writeChunk(destination, charsetChunks[i]);
+ }
+
+ charsetChunks.length = 0; // emit preconnect resources
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Flush unblocked stylesheets by precedence
+
+ renderState.styles.forEach(flushStylesInPreamble, destination);
+ const importMapChunks = renderState.importMapChunks;
+
+ for (i = 0; i < importMapChunks.length; i++) {
+ writeChunk(destination, importMapChunks[i]);
+ }
+
+ importMapChunks.length = 0;
+ renderState.bootstrapScripts.forEach(flushResource, destination);
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0; // Flush closing head if necessary
+
+ if (htmlChunks && headChunks === null) {
+ // We have an rendered but no rendered. We however inserted
+ // a up above so we need to emit the now. This is safe because
+ // if the main content contained the it would also have provided a
+ // . This means that all the content inside is either or
+ // invalid HTML
+ writeChunk(destination, endChunkForTag('head'));
+ }
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+function writeHoistables(destination, resumableState, renderState) {
+ let i = 0; // Emit high priority Hoistables
+ // We omit charsetChunks because we have already sent the shell and if it wasn't
+ // already sent it is too late now.
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Preload any stylesheets. these will emit in a render instruction that follows this
+ // but we want to kick off preloading as soon as possible
+
+ renderState.styles.forEach(preloadLateStyles, destination); // We only hoist importmaps that are configured through createResponse and that will
+ // always flush in the preamble. Generally we don't expect people to render them as
+ // tags when using React but if you do they are going to be treated like regular inline
+ // scripts and flush after other hoistables which is problematic
+ // bootstrap scripts should flush above script priority but these can only flush in the preamble
+ // so we elide the code here for performance
+
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0;
+}
+function writePostamble(destination, resumableState) {
+ if (resumableState.hasBody) {
+ writeChunk(destination, endChunkForTag('body'));
+ }
+
+ if (resumableState.hasHtml) {
+ writeChunk(destination, endChunkForTag('html'));
+ }
+}
+const arrayFirstOpenBracket = stringToPrecomputedChunk('[');
+const arraySubsequentOpenBracket = stringToPrecomputedChunk(',[');
+const arrayInterstitial = stringToPrecomputedChunk(',');
+const arrayCloseBracket = stringToPrecomputedChunk(']'); // This function writes a 2D array of strings to be embedded in javascript.
+// E.g.
+// [["JS_escaped_string1", "JS_escaped_string2"]]
+
+function writeStyleResourceDependenciesInJS(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInJS(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInJS(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInJS(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+}
+
+function writeStyleResourceDependencyInJS(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedPrecedence)));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInJS(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInJS(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeName)));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeValue)));
+} // This function writes a 2D array of strings to be embedded in an attribute
+// value and read with JSON.parse in ReactDOMServerExternalRuntime.js
+// E.g.
+// [["JSON_escaped_string1", "JSON_escaped_string2"]]
+
+
+function writeStyleResourceDependenciesInAttr(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInAttr(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInAttr(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInAttr(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+}
+
+function writeStyleResourceDependencyInAttr(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedPrecedence))));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInAttr(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInAttr(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeName))));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeValue))));
+}
+/**
+ * Resources
+ */
+
+
+const PENDING$1 = 0;
+const PRELOADED = 1;
+const PREAMBLE = 2;
+const LATE = 3;
+function createBoundaryResources() {
+ return {
+ styles: new Set(),
+ stylesheets: new Set()
+ };
+}
+function setCurrentlyRenderingBoundaryResourcesTarget(renderState, boundaryResources) {
+ renderState.boundaryResources = boundaryResources;
+}
+
+function getResourceKey(href) {
+ return href;
+}
+
+function getImageResourceKey(href, imageSrcSet, imageSizes) {
+ if (imageSrcSet) {
+ return imageSrcSet + '\n' + (imageSizes || '');
+ }
+
+ return href;
+}
+
+function prefetchDNS(href) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const key = getResourceKey(href);
+
+ if (!resumableState.dnsResources.hasOwnProperty(key)) {
+ resumableState.dnsResources[key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPrefetchDNSAsHeader(href), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this as resettable in case we are prerendering and postpone in the Shell
+ renderState.resets.dns[key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ // Encode as element
+ const resource = [];
+ pushLinkImpl(resource, {
+ href,
+ rel: 'dns-prefetch'
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preconnect(href, crossOrigin) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const bucket = crossOrigin === 'use-credentials' ? 'credentials' : typeof crossOrigin === 'string' ? 'anonymous' : 'default';
+ const key = getResourceKey(href);
+
+ if (!resumableState.connectResources[bucket].hasOwnProperty(key)) {
+ resumableState.connectResources[bucket][key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreconnectAsHeader(href, crossOrigin), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this in resettableState in case we are prerending and postpone in the Shell
+ renderState.resets.connect[bucket][key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ const resource = [];
+ pushLinkImpl(resource, {
+ rel: 'preconnect',
+ href,
+ crossOrigin
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preload(href, as, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (as && href) {
+ switch (as) {
+ case 'image':
+ {
+ let imageSrcSet, imageSizes, fetchPriority;
+
+ if (options) {
+ imageSrcSet = options.imageSrcSet;
+ imageSizes = options.imageSizes;
+ fetchPriority = options.fetchPriority;
+ }
+
+ const key = getImageResourceKey(href, imageSrcSet, imageSizes);
+
+ if (resumableState.imageResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resumableState.imageResources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && fetchPriority === 'high' && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit a preload as a header so we
+ // track this to make sure we don't reset it.
+ renderState.resets.image[key] = PRELOAD_NO_CREDS;
+
+ if (headers.highImagePreloads) {
+ headers.highImagePreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.highImagePreloads += header;
+ } else {
+ // If we don't have headers to write to we have to encode as elements to flush in the head
+ // When we have imageSrcSet the browser probably cannot load the right version from headers
+ // (this should be verified by testing). For now we assume these need to go in the head
+ // as elements even if headers are available.
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ // There is a bug in Safari where imageSrcSet is not respected on preload links
+ // so we omit the href here if we have imageSrcSet b/c safari will load the wrong image.
+ // This harms older browers that do not support imageSrcSet by making their preloads not work
+ // but this population is shrinking fast and is already small so we accept this tradeoff.
+ href: imageSrcSet ? undefined : href,
+ as
+ }, options));
+
+ if (fetchPriority === 'high') {
+ renderState.highImagePreloads.add(resource);
+ } else {
+ renderState.bulkPreloads.add(resource); // Stash the resource in case we need to promote it to higher priority
+ // when an img tag is rendered
+
+ renderState.preloads.images.set(key, resource);
+ }
+ }
+
+ break;
+ }
+
+ case 'style':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.styleResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.styleResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.stylesheets.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ break;
+ }
+
+ case 'script':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.scriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ renderState.preloads.scripts.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.scriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ break;
+ }
+
+ default:
+ {
+ const key = getResourceKey(href);
+ const hasAsType = resumableState.unknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.unknownResources[as] = resources;
+ }
+
+ resources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && as === 'font' && ( // We compute the header here because we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit this preload so we
+ // track it here to prevent it from being reset.
+ renderState.resets.font[key] = PRELOAD_NO_CREDS;
+
+ if (headers.fontPreloads) {
+ headers.fontPreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.fontPreloads += header;
+ } else {
+ // We either don't have headers or we are preloading something that does
+ // not warrant elevated priority so we encode as an element.
+ const resource = [];
+
+ const props = assign({
+ rel: 'preload',
+ href,
+ as
+ }, options);
+
+ pushLinkImpl(resource, props);
+
+ switch (as) {
+ case 'font':
+ renderState.fontPreloads.add(resource);
+ break;
+ // intentional fall through
+
+ default:
+ renderState.bulkPreloads.add(resource);
+ }
+ }
+ }
+ } // If we got this far we created a new resource
+
+
+ flushResources(request);
+ }
+}
+
+function preloadModule(href, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ const key = getResourceKey(href);
+ const as = options && typeof options.as === 'string' ? options.as : 'script';
+ let resource;
+
+ switch (as) {
+ case 'script':
+ {
+ if (resumableState.moduleScriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resource = [];
+ resumableState.moduleScriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.moduleScripts.set(key, resource);
+ break;
+ }
+
+ default:
+ {
+ const hasAsType = resumableState.moduleUnknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.moduleUnknownResources[as] = resources;
+ }
+
+ resource = [];
+ resources[key] = PRELOAD_NO_CREDS;
+ }
+ }
+
+ pushLinkImpl(resource, assign({
+ rel: 'modulepreload',
+ href
+ }, options));
+ renderState.bulkPreloads.add(resource); // If we got this far we created a new resource
+
+ flushResources(request);
+ }
+}
+
+function preinitStyle(href, precedence, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ precedence = precedence || 'default';
+ const key = getResourceKey(href);
+ let styleQueue = renderState.styles.get(precedence);
+ const hasKey = resumableState.styleResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.styleResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.styleResources[key] = EXISTS; // If this is the first time we've encountered this precedence we need
+ // to create a StyleQueue
+
+ if (!styleQueue) {
+ styleQueue = {
+ precedence: stringToChunk(escapeTextForBrowser(precedence)),
+ rules: [],
+ hrefs: [],
+ sheets: new Map()
+ };
+ renderState.styles.set(precedence, styleQueue);
+ }
+
+ const resource = {
+ state: PENDING$1,
+ props: assign({
+ rel: 'stylesheet',
+ href,
+ 'data-precedence': precedence
+ }, options)
+ };
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(resource.props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.stylesheets.get(key);
+
+ if (preloadResource && preloadResource.length > 0) {
+ // The Preload for this resource was created in this render pass and has not flushed yet so
+ // we need to clear it to avoid it flushing.
+ preloadResource.length = 0;
+ } else {
+ // Either the preload resource from this render already flushed in this render pass
+ // or the preload flushed in a prior pass (prerender). In either case we need to mark
+ // this resource as already having been preloaded.
+ resource.state = PRELOADED;
+ }
+ } // We add the newly created resource to our StyleQueue and if necessary
+ // track the resource with the currently rendering boundary
+
+
+ styleQueue.sheets.set(key, resource); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+ }
+}
+
+function preinitScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.scriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.scriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.scriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.scripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+}
+
+function preinitModuleScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.moduleScriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.moduleScriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.moduleScriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ type: 'module',
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.moduleScripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+} // This function is only safe to call at Request start time since it assumes
+// that each module has not already been preloaded. If we find a need to preload
+// scripts at any other point in time we will need to check whether the preload
+// already exists and not assume it
+
+
+function preloadBootstrapScriptOrModule(resumableState, renderState, href, props) {
+
+ const key = getResourceKey(href);
+ // used to preinit the resource. If a script can be preinited then it shouldn't
+ // be a bootstrap script/module and if it is a bootstrap script/module then it
+ // must not be safe to emit early. To avoid possibly allowing for preinits of
+ // bootstrap scripts/modules we occlude these keys.
+
+
+ resumableState.scriptResources[key] = EXISTS;
+ resumableState.moduleScriptResources[key] = EXISTS;
+ const resource = [];
+ pushLinkImpl(resource, props);
+ renderState.bootstrapScripts.add(resource);
+}
+
+function internalPreinitScript(resumableState, renderState, src, chunks) {
+ const key = getResourceKey(src);
+
+ if (!resumableState.scriptResources.hasOwnProperty(key)) {
+ const resource = chunks;
+ resumableState.scriptResources[key] = EXISTS;
+ renderState.scripts.add(resource);
+ }
+
+ return;
+}
+
+function preloadAsStylePropsFromProps(href, props) {
+ return {
+ rel: 'preload',
+ as: 'style',
+ href: href,
+ crossOrigin: props.crossOrigin,
+ fetchPriority: props.fetchPriority,
+ integrity: props.integrity,
+ media: props.media,
+ hrefLang: props.hrefLang,
+ referrerPolicy: props.referrerPolicy
+ };
+}
+
+function stylesheetPropsFromRawProps(rawProps) {
+ return assign({}, rawProps, {
+ 'data-precedence': rawProps.precedence,
+ precedence: null
+ });
+}
+
+function adoptPreloadCredentials(target, preloadState) {
+ if (target.crossOrigin == null) target.crossOrigin = preloadState[0];
+ if (target.integrity == null) target.integrity = preloadState[1];
+}
+
+function getPrefetchDNSAsHeader(href) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ return "<" + escapedHref + ">; rel=dns-prefetch";
+}
+
+function getPreconnectAsHeader(href, crossOrigin) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ let value = "<" + escapedHref + ">; rel=preconnect";
+
+ if (typeof crossOrigin === 'string') {
+ const escapedCrossOrigin = escapeStringForLinkHeaderQuotedParamValueContext(crossOrigin);
+ value += "; crossorigin=\"" + escapedCrossOrigin + "\"";
+ }
+
+ return value;
+}
+
+function getPreloadAsHeader(href, as, params) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ const escapedAs = escapeStringForLinkHeaderQuotedParamValueContext(as);
+ let value = "<" + escapedHref + ">; rel=preload; as=\"" + escapedAs + "\"";
+
+ for (const paramName in params) {
+ if (hasOwnProperty.call(params, paramName)) {
+ const paramValue = params[paramName];
+
+ if (typeof paramValue === 'string') {
+ value += "; " + paramName.toLowerCase() + "=\"" + escapeStringForLinkHeaderQuotedParamValueContext(paramValue) + "\"";
+ }
+ }
+ }
+
+ return value;
+}
+
+function getStylesheetPreloadAsHeader(stylesheet) {
+ const props = stylesheet.props;
+ const preloadOptions = {
+ crossOrigin: props.crossOrigin,
+ integrity: props.integrity,
+ nonce: props.nonce,
+ type: props.type,
+ fetchPriority: props.fetchPriority,
+ referrerPolicy: props.referrerPolicy,
+ media: props.media
+ };
+ return getPreloadAsHeader(props.href, 'style', preloadOptions);
+} // This escaping function is only safe to use for href values being written into
+// a "Link" header in between `<` and `>` characters. The primary concern with the href is
+// to escape the bounding characters as well as new lines. This is unsafe to use in any other
+// context
+
+
+const regexForHrefInLinkHeaderURLContext = /[<>\r\n]/g;
+
+function escapeHrefForLinkHeaderURLContext(hrefInput) {
+
+ const coercedHref = '' + hrefInput;
+ return coercedHref.replace(regexForHrefInLinkHeaderURLContext, escapeHrefForLinkHeaderURLContextReplacer);
+}
+
+function escapeHrefForLinkHeaderURLContextReplacer(match) {
+ switch (match) {
+ case '<':
+ return '%3C';
+
+ case '>':
+ return '%3E';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+} // This escaping function is only safe to use for quoted param values in an HTTP header.
+// It is unsafe to use for any value not inside quote marks in parater value position.
+
+
+const regexForLinkHeaderQuotedParamValueContext = /["';,\r\n]/g;
+
+function escapeStringForLinkHeaderQuotedParamValueContext(value, name) {
+
+ const coerced = '' + value;
+ return coerced.replace(regexForLinkHeaderQuotedParamValueContext, escapeStringForLinkHeaderQuotedParamValueContextReplacer);
+}
+
+function escapeStringForLinkHeaderQuotedParamValueContextReplacer(match) {
+ switch (match) {
+ case '"':
+ return '%22';
+
+ case "'":
+ return '%27';
+
+ case ';':
+ return '%3B';
+
+ case ',':
+ return '%2C';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+}
+
+function hoistStyleQueueDependency(styleQueue) {
+ this.styles.add(styleQueue);
+}
+
+function hoistStylesheetDependency(stylesheet) {
+ this.stylesheets.add(stylesheet);
+}
+
+function hoistResources(renderState, source) {
+ const currentBoundaryResources = renderState.boundaryResources;
+
+ if (currentBoundaryResources) {
+ source.styles.forEach(hoistStyleQueueDependency, currentBoundaryResources);
+ source.stylesheets.forEach(hoistStylesheetDependency, currentBoundaryResources);
+ }
+} // This function is called at various times depending on whether we are rendering
+// or prerendering. In this implementation we only actually emit headers once and
+// subsequent calls are ignored. We track whether the request has a completed shell
+// to determine whether we will follow headers with a flush including stylesheets.
+// In the context of prerrender we don't have a completed shell when the request finishes
+// with a postpone in the shell. In the context of a render we don't have a completed shell
+// if this is called before the shell finishes rendering which usually will happen anytime
+// anything suspends in the shell.
+
+function emitEarlyPreloads(renderState, resumableState, shellComplete) {
+ const onHeaders = renderState.onHeaders;
+
+ if (onHeaders) {
+ const headers = renderState.headers;
+
+ if (headers) {
+ let linkHeader = headers.preconnects;
+
+ if (headers.fontPreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.fontPreloads;
+ }
+
+ if (headers.highImagePreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.highImagePreloads;
+ }
+
+ if (!shellComplete) {
+ // We use raw iterators because we want to be able to halt iteration
+ // We could refactor renderState to store these dually in arrays to
+ // make this more efficient at the cost of additional memory and
+ // write overhead. However this code only runs once per request so
+ // for now I consider this sufficient.
+ const queueIter = renderState.styles.values();
+
+ outer: for (let queueStep = queueIter.next(); headers.remainingCapacity > 0 && !queueStep.done; queueStep = queueIter.next()) {
+ const sheets = queueStep.value.sheets;
+ const sheetIter = sheets.values();
+
+ for (let sheetStep = sheetIter.next(); headers.remainingCapacity > 0 && !sheetStep.done; sheetStep = sheetIter.next()) {
+ const sheet = sheetStep.value;
+ const props = sheet.props;
+ const key = getResourceKey(props.href);
+ const header = getStylesheetPreloadAsHeader(sheet); // We mutate the capacity b/c we don't want to keep checking if later headers will fit.
+ // This means that a particularly long header might close out the header queue where later
+ // headers could still fit. We could in the future alter the behavior here based on prerender vs render
+ // since during prerender we aren't as concerned with pure runtime performance.
+
+ if ((headers.remainingCapacity -= header.length) >= 2) {
+ renderState.resets.style[key] = PRELOAD_NO_CREDS;
+
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += header; // We already track that the resource exists in resumableState however
+ // if the resumableState resets because we postponed in the shell
+ // which is what is happening in this branch if we are prerendering
+ // then we will end up resetting the resumableState. When it resets we
+ // want to record the fact that this stylesheet was already preloaded
+
+ renderState.resets.style[key] = typeof props.crossOrigin === 'string' || typeof props.integrity === 'string' ? [props.crossOrigin, props.integrity] : PRELOAD_NO_CREDS;
+ } else {
+ break outer;
+ }
+ }
+ }
+ }
+
+ if (linkHeader) {
+ onHeaders({
+ Link: linkHeader
+ });
+ } else {
+ // We still call this with no headers because a user may be using it as a signal that
+ // it React will not provide any headers
+ onHeaders({});
+ }
+
+ renderState.headers = null;
+ return;
+ }
+ }
+}
+const NotPendingTransition = NotPending;
+
+const supportsRequestStorage = typeof AsyncLocalStorage === 'function';
+const requestStorage = supportsRequestStorage ? new AsyncLocalStorage() : null;
+
+// ATTENTION
+// When adding new symbols to this file,
+// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
+// The Symbol used to tag the ReactElement-like types.
+const REACT_ELEMENT_TYPE = Symbol.for('react.element');
+const REACT_PORTAL_TYPE = Symbol.for('react.portal');
+const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
+const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
+const REACT_PROFILER_TYPE = Symbol.for('react.profiler');
+const REACT_PROVIDER_TYPE = Symbol.for('react.provider');
+const REACT_CONTEXT_TYPE = Symbol.for('react.context');
+const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
+const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
+const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
+const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
+const REACT_MEMO_TYPE = Symbol.for('react.memo');
+const REACT_LAZY_TYPE = Symbol.for('react.lazy');
+const REACT_SCOPE_TYPE = Symbol.for('react.scope');
+const REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');
+const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
+const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');
+const REACT_CACHE_TYPE = Symbol.for('react.cache');
+const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value');
+const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
+const FAUX_ITERATOR_SYMBOL = '@@iterator';
+function getIteratorFn(maybeIterable) {
+ if (maybeIterable === null || typeof maybeIterable !== 'object') {
+ return null;
+ }
+
+ const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
+
+ if (typeof maybeIterator === 'function') {
+ return maybeIterator;
+ }
+
+ return null;
+}
+
+function getWrappedName(outerType, innerType, wrapperName) {
+ const displayName = outerType.displayName;
+
+ if (displayName) {
+ return displayName;
+ }
+
+ const functionName = innerType.displayName || innerType.name || '';
+ return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName;
+} // Keep in sync with react-reconciler/getComponentNameFromFiber
+
+
+function getContextName(type) {
+ return type.displayName || 'Context';
+} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+
+
+function getComponentNameFromType(type) {
+ if (type == null) {
+ // Host root, text node or just invalid type.
+ return null;
+ }
+
+ if (typeof type === 'function') {
+ return type.displayName || type.name || null;
+ }
+
+ if (typeof type === 'string') {
+ return type;
+ }
+
+ switch (type) {
+ case REACT_FRAGMENT_TYPE:
+ return 'Fragment';
+
+ case REACT_PORTAL_TYPE:
+ return 'Portal';
+
+ case REACT_PROFILER_TYPE:
+ return 'Profiler';
+
+ case REACT_STRICT_MODE_TYPE:
+ return 'StrictMode';
+
+ case REACT_SUSPENSE_TYPE:
+ return 'Suspense';
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ return 'SuspenseList';
+
+ case REACT_CACHE_TYPE:
+ {
+ return 'Cache';
+ }
+
+ }
+
+ if (typeof type === 'object') {
+ switch (type.$$typeof) {
+ case REACT_CONTEXT_TYPE:
+ const context = type;
+ return getContextName(context) + '.Consumer';
+
+ case REACT_PROVIDER_TYPE:
+ const provider = type;
+ return getContextName(provider._context) + '.Provider';
+
+ case REACT_FORWARD_REF_TYPE:
+ return getWrappedName(type, type.render, 'ForwardRef');
+
+ case REACT_MEMO_TYPE:
+ const outerName = type.displayName || null;
+
+ if (outerName !== null) {
+ return outerName;
+ }
+
+ return getComponentNameFromType(type.type) || 'Memo';
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyComponent = type;
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+
+ try {
+ return getComponentNameFromType(init(payload));
+ } catch (x) {
+ return null;
+ }
+ }
+
+ }
+ }
+
+ return null;
+}
+
+const emptyContextObject = {};
+
+function getMaskedContext(type, unmaskedContext) {
+ {
+ const contextTypes = type.contextTypes;
+
+ if (!contextTypes) {
+ return emptyContextObject;
+ }
+
+ const context = {};
+
+ for (const key in contextTypes) {
+ context[key] = unmaskedContext[key];
+ }
+
+ return context;
+ }
+}
+function processChildContext(instance, type, parentContext, childContextTypes) {
+ {
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
+ if (typeof instance.getChildContext !== 'function') {
+
+ return parentContext;
+ }
+
+ const childContext = instance.getChildContext();
+
+ for (const contextKey in childContext) {
+ if (!(contextKey in childContextTypes)) {
+ throw new Error((getComponentNameFromType(type) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes.");
+ }
+ }
+
+ return assign({}, parentContext, childContext);
+ }
+}
+
+// Forming a reverse tree.
+// The structure of a context snapshot is an implementation of this file.
+// Currently, it's implemented as tracking the current active node.
+
+
+const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
+// This global (actually thread local) state represents what state all those "current",
+// fields are currently in.
+
+let currentActiveSnapshot = null;
+
+function popNode(prev) {
+ {
+ prev.context._currentValue = prev.parentValue;
+ }
+}
+
+function pushNode(next) {
+ {
+ next.context._currentValue = next.value;
+ }
+}
+
+function popToNearestCommonAncestor(prev, next) {
+ if (prev === next) ; else {
+ popNode(prev);
+ const parentPrev = prev.parent;
+ const parentNext = next.parent;
+
+ if (parentPrev === null) {
+ if (parentNext !== null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+ } else {
+ if (parentNext === null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+
+ popToNearestCommonAncestor(parentPrev, parentNext);
+ } // On the way back, we push the new ones that weren't common.
+
+
+ pushNode(next);
+ }
+}
+
+function popAllPrevious(prev) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev !== null) {
+ popAllPrevious(parentPrev);
+ }
+}
+
+function pushAllNext(next) {
+ const parentNext = next.parent;
+
+ if (parentNext !== null) {
+ pushAllNext(parentNext);
+ }
+
+ pushNode(next);
+}
+
+function popPreviousToCommonLevel(prev, next) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (parentPrev.depth === next.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(parentPrev, next);
+ } else {
+ // We must still be deeper.
+ popPreviousToCommonLevel(parentPrev, next);
+ }
+}
+
+function popNextToCommonLevel(prev, next) {
+ const parentNext = next.parent;
+
+ if (parentNext === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (prev.depth === parentNext.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(prev, parentNext);
+ } else {
+ // We must still be deeper.
+ popNextToCommonLevel(prev, parentNext);
+ }
+
+ pushNode(next);
+} // Perform context switching to the new snapshot.
+// To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
+// updating all the context's current values. That way reads, always just read the current value.
+// At the cost of updating contexts even if they're never read by this subtree.
+
+
+function switchContext(newSnapshot) {
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
+ // We also need to update any new contexts that are now on the stack with the deepest value.
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
+ // for that. Therefore this algorithm is recursive.
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
+ // 3) Then we reapply new contexts on the way back up the stack.
+ const prev = currentActiveSnapshot;
+ const next = newSnapshot;
+
+ if (prev !== next) {
+ if (prev === null) {
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
+ pushAllNext(next);
+ } else if (next === null) {
+ popAllPrevious(prev);
+ } else if (prev.depth === next.depth) {
+ popToNearestCommonAncestor(prev, next);
+ } else if (prev.depth > next.depth) {
+ popPreviousToCommonLevel(prev, next);
+ } else {
+ popNextToCommonLevel(prev, next);
+ }
+
+ currentActiveSnapshot = next;
+ }
+}
+function pushProvider(context, nextValue) {
+ let prevValue;
+
+ {
+ prevValue = context._currentValue;
+ context._currentValue = nextValue;
+ }
+
+ const prevNode = currentActiveSnapshot;
+ const newNode = {
+ parent: prevNode,
+ depth: prevNode === null ? 0 : prevNode.depth + 1,
+ context: context,
+ parentValue: prevValue,
+ value: nextValue
+ };
+ currentActiveSnapshot = newNode;
+ return newNode;
+}
+function popProvider(context) {
+ const prevSnapshot = currentActiveSnapshot;
+
+ if (prevSnapshot === null) {
+ throw new Error('Tried to pop a Context at the root of the app. This is a bug in React.');
+ }
+
+ {
+ const value = prevSnapshot.parentValue;
+
+ if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) {
+ prevSnapshot.context._currentValue = prevSnapshot.context._defaultValue;
+ } else {
+ prevSnapshot.context._currentValue = value;
+ }
+ }
+
+ return currentActiveSnapshot = prevSnapshot.parent;
+}
+function getActiveContext() {
+ return currentActiveSnapshot;
+}
+function readContext$1(context) {
+ const value = context._currentValue ;
+ return value;
+}
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ *
+ * Note that this module is currently shared and assumed to be stateless.
+ * If this becomes an actual Map, that will break.
+ */
+function get(key) {
+ return key._reactInternals;
+}
+function set(key, value) {
+ key._reactInternals = value;
+}
+
+const classComponentUpdater = {
+ isMounted(inst) {
+ return false;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueSetState(inst, payload, callback) {
+ const internals = get(inst);
+
+ if (internals.queue === null) ; else {
+ internals.queue.push(payload);
+ }
+ },
+
+ enqueueReplaceState(inst, payload, callback) {
+ const internals = get(inst);
+ internals.replace = true;
+ internals.queue = [payload];
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueForceUpdate(inst, callback) {
+ }
+
+};
+
+function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) {
+ const partialState = getDerivedStateFromProps(nextProps, prevState);
+
+
+ const newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);
+ return newState;
+}
+
+function constructClassInstance(ctor, props, maskedLegacyContext) {
+ let context = emptyContextObject;
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ context = readContext$1(contextType);
+ } else {
+ context = maskedLegacyContext;
+ }
+
+ const instance = new ctor(props, context);
+
+ return instance;
+}
+
+function callComponentWillMount(type, instance) {
+ const oldState = instance.state;
+
+ if (typeof instance.componentWillMount === 'function') {
+
+ instance.componentWillMount();
+ }
+
+ if (typeof instance.UNSAFE_componentWillMount === 'function') {
+ instance.UNSAFE_componentWillMount();
+ }
+
+ if (oldState !== instance.state) {
+
+ classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
+ }
+}
+
+function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) {
+ if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
+ const oldQueue = internalInstance.queue;
+ const oldReplace = internalInstance.replace;
+ internalInstance.queue = null;
+ internalInstance.replace = false;
+
+ if (oldReplace && oldQueue.length === 1) {
+ inst.state = oldQueue[0];
+ } else {
+ let nextState = oldReplace ? oldQueue[0] : inst.state;
+ let dontMutate = true;
+
+ for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
+ const partial = oldQueue[i];
+ const partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial;
+
+ if (partialState != null) {
+ if (dontMutate) {
+ dontMutate = false;
+ nextState = assign({}, nextState, partialState);
+ } else {
+ assign(nextState, partialState);
+ }
+ }
+ }
+
+ inst.state = nextState;
+ }
+ } else {
+ internalInstance.queue = null;
+ }
+} // Invokes the mount life-cycles on a previously never rendered instance.
+
+
+function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) {
+
+ const initialState = instance.state !== undefined ? instance.state : null;
+ instance.updater = classComponentUpdater;
+ instance.props = newProps;
+ instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway.
+ // The internal instance will be used to manage updates that happen during this mount.
+
+ const internalInstance = {
+ queue: [],
+ replace: false
+ };
+ set(instance, internalInstance);
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ instance.context = readContext$1(contextType);
+ } else {
+ instance.context = maskedLegacyContext;
+ }
+
+ const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
+
+ if (typeof getDerivedStateFromProps === 'function') {
+ instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps);
+ } // In order to support react-lifecycles-compat polyfilled components,
+ // Unsafe lifecycles should not be invoked for components using the new APIs.
+
+
+ if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
+ callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's
+ // process them now.
+
+ processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext);
+ }
+}
+
+// Ids are base 32 strings whose binary representation corresponds to the
+// position of a node in a tree.
+// Every time the tree forks into multiple children, we add additional bits to
+// the left of the sequence that represent the position of the child within the
+// current level of children.
+//
+// 00101 00010001011010101
+// ╰─┬─╯ ╰───────┬───────╯
+// Fork 5 of 20 Parent id
+//
+// The leading 0s are important. In the above example, you only need 3 bits to
+// represent slot 5. However, you need 5 bits to represent all the forks at
+// the current level, so we must account for the empty bits at the end.
+//
+// For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise,
+// the zeroth id at a level would be indistinguishable from its parent.
+//
+// If a node has only one child, and does not materialize an id (i.e. does not
+// contain a useId hook), then we don't need to allocate any space in the
+// sequence. It's treated as a transparent indirection. For example, these two
+// trees produce the same ids:
+//
+// <> <>
+//
+//
+// >
+//
+// >
+//
+// However, we cannot skip any node that materializes an id. Otherwise, a parent
+// id that does not fork would be indistinguishable from its child id. For
+// example, this tree does not fork, but the parent and child must have
+// different ids.
+//
+//
+//
+//
+//
+// To handle this scenario, every time we materialize an id, we allocate a
+// new level with a single slot. You can think of this as a fork with only one
+// prong, or an array of children with length 1.
+//
+// It's possible for the size of the sequence to exceed 32 bits, the max
+// size for bitwise operations. When this happens, we make more room by
+// converting the right part of the id to a string and storing it in an overflow
+// variable. We use a base 32 string representation, because 32 is the largest
+// power of 2 that is supported by toString(). We want the base to be large so
+// that the resulting ids are compact, and we want the base to be a power of 2
+// because every log2(base) bits corresponds to a single character, i.e. every
+// log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without
+// affecting the final result.
+const emptyTreeContext = {
+ id: 1,
+ overflow: ''
+};
+function getTreeId(context) {
+ const overflow = context.overflow;
+ const idWithLeadingBit = context.id;
+ const id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);
+ return id.toString(32) + overflow;
+}
+function pushTreeContext(baseContext, totalChildren, index) {
+ const baseIdWithLeadingBit = baseContext.id;
+ const baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part
+ // of the id; we use it to account for leading 0s.
+
+ const baseLength = getBitLength(baseIdWithLeadingBit) - 1;
+ const baseId = baseIdWithLeadingBit & ~(1 << baseLength);
+ const slot = index + 1;
+ const length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into
+ // consideration the leading 1 we use to mark the end of the sequence.
+
+ if (length > 30) {
+ // We overflowed the bitwise-safe range. Fall back to slower algorithm.
+ // This branch assumes the length of the base id is greater than 5; it won't
+ // work for smaller ids, because you need 5 bits per character.
+ //
+ // We encode the id in multiple steps: first the base id, then the
+ // remaining digits.
+ //
+ // Each 5 bit sequence corresponds to a single base 32 character. So for
+ // example, if the current id is 23 bits long, we can convert 20 of those
+ // bits into a string of 4 characters, with 3 bits left over.
+ //
+ // First calculate how many bits in the base id represent a complete
+ // sequence of characters.
+ const numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.
+
+ const newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.
+
+ const newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.
+
+ const restOfBaseId = baseId >> numberOfOverflowBits;
+ const restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because
+ // we made more room, this time it won't overflow.
+
+ const restOfLength = getBitLength(totalChildren) + restOfBaseLength;
+ const restOfNewBits = slot << restOfBaseLength;
+ const id = restOfNewBits | restOfBaseId;
+ const overflow = newOverflow + baseOverflow;
+ return {
+ id: 1 << restOfLength | id,
+ overflow
+ };
+ } else {
+ // Normal path
+ const newBits = slot << baseLength;
+ const id = newBits | baseId;
+ const overflow = baseOverflow;
+ return {
+ id: 1 << length | id,
+ overflow
+ };
+ }
+}
+
+function getBitLength(number) {
+ return 32 - clz32(number);
+}
+
+function getLeadingBit(id) {
+ return 1 << getBitLength(id) - 1;
+} // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback.
+
+
+const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.
+// Based on:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+const log = Math.log;
+const LN2 = Math.LN2;
+
+function clz32Fallback(x) {
+ const asUint = x >>> 0;
+
+ if (asUint === 0) {
+ return 32;
+ }
+
+ return 31 - (log(asUint) / LN2 | 0) | 0;
+}
+
+// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
+// changes to one module should be reflected in the others.
+// TODO: Rename this module and the corresponding Fiber one to "Thenable"
+// instead of "Wakeable". Or some other more appropriate name.
+// An error that is thrown (e.g. by `use`) to trigger Suspense. If we
+// detect this is caught by userspace, we'll log a warning in development.
+const SuspenseException = new Error("Suspense Exception: This is not a real error! It's an implementation " + 'detail of `use` to interrupt the current render. You must either ' + 'rethrow it immediately, or move the `use` call outside of the ' + '`try/catch` block. Capturing without rethrowing will lead to ' + 'unexpected behavior.\n\n' + 'To handle async errors, wrap your component in an error boundary, or ' + "call the promise's `.catch` method and pass the result to `use`");
+function createThenableState() {
+ // The ThenableState is created the first time a component suspends. If it
+ // suspends again, we'll reuse the same state.
+ return [];
+}
+
+function noop$2() {}
+
+function trackUsedThenable(thenableState, thenable, index) {
+ const previous = thenableState[index];
+
+ if (previous === undefined) {
+ thenableState.push(thenable);
+ } else {
+ if (previous !== thenable) {
+ // Reuse the previous thenable, and drop the new one. We can assume
+ // they represent the same value, because components are idempotent.
+ // Avoid an unhandled rejection errors for the Promises that we'll
+ // intentionally ignore.
+ thenable.then(noop$2, noop$2);
+ thenable = previous;
+ }
+ } // We use an expando to track the status and result of a thenable so that we
+ // can synchronously unwrap the value. Think of this as an extension of the
+ // Promise API, or a custom interface that is a superset of Thenable.
+ //
+ // If the thenable doesn't have a status, set it to "pending" and attach
+ // a listener that will update its status and result when it resolves.
+
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledValue = thenable.value;
+ return fulfilledValue;
+ }
+
+ case 'rejected':
+ {
+ const rejectedError = thenable.reason;
+ throw rejectedError;
+ }
+
+ default:
+ {
+ if (typeof thenable.status === 'string') ; else {
+ const pendingThenable = thenable;
+ pendingThenable.status = 'pending';
+ pendingThenable.then(fulfilledValue => {
+ if (thenable.status === 'pending') {
+ const fulfilledThenable = thenable;
+ fulfilledThenable.status = 'fulfilled';
+ fulfilledThenable.value = fulfilledValue;
+ }
+ }, error => {
+ if (thenable.status === 'pending') {
+ const rejectedThenable = thenable;
+ rejectedThenable.status = 'rejected';
+ rejectedThenable.reason = error;
+ }
+ }); // Check one more time in case the thenable resolved synchronously
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledThenable = thenable;
+ return fulfilledThenable.value;
+ }
+
+ case 'rejected':
+ {
+ const rejectedThenable = thenable;
+ throw rejectedThenable.reason;
+ }
+ }
+ } // Suspend.
+ //
+ // Throwing here is an implementation detail that allows us to unwind the
+ // call stack. But we shouldn't allow it to leak into userspace. Throw an
+ // opaque placeholder value instead of the actual thenable. If it doesn't
+ // get captured by the work loop, log a warning, because that means
+ // something in userspace must have caught it.
+
+
+ suspendedThenable = thenable;
+ throw SuspenseException;
+ }
+ }
+} // This is used to track the actual thenable that suspended so it can be
+// passed to the rest of the Suspense implementation — which, for historical
+// reasons, expects to receive a thenable.
+
+let suspendedThenable = null;
+function getSuspendedThenable() {
+ // This is called right after `use` suspends by throwing an exception. `use`
+ // throws an opaque value instead of the thenable itself so that it can't be
+ // caught in userspace. Then the work loop accesses the actual thenable using
+ // this function.
+ if (suspendedThenable === null) {
+ throw new Error('Expected a suspended thenable. This is a bug in React. Please file ' + 'an issue.');
+ }
+
+ const thenable = suspendedThenable;
+ suspendedThenable = null;
+ return thenable;
+}
+
+/**
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+ */
+function is(x, y) {
+ return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
+ ;
+}
+
+const objectIs = // $FlowFixMe[method-unbinding]
+typeof Object.is === 'function' ? Object.is : is;
+
+let currentlyRenderingComponent = null;
+let currentlyRenderingTask = null;
+let currentlyRenderingRequest = null;
+let currentlyRenderingKeyPath = null;
+let firstWorkInProgressHook = null;
+let workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook
+
+let isReRender = false; // Whether an update was scheduled during the currently executing render pass.
+
+let didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component
+
+let localIdCounter = 0; // Chunks that should be pushed to the stream once the component
+// finishes rendering.
+// Counts the number of useFormState calls in this component
+
+let formStateCounter = 0; // The index of the useFormState hook that matches the one passed in at the
+// root during an MPA navigation, if any.
+
+let formStateMatchingIndex = -1; // Counts the number of use(thenable) calls in this component
+
+let thenableIndexCounter = 0;
+let thenableState = null; // Lazily created map of render-phase updates
+
+let renderPhaseUpdates = null; // Counter to prevent infinite loops.
+
+let numberOfReRenders = 0;
+const RE_RENDER_LIMIT = 25;
+
+function resolveCurrentlyRenderingComponent() {
+ if (currentlyRenderingComponent === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + '2. You might be breaking the Rules of Hooks\n' + '3. You might have more than one copy of React in the same app\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.');
+ }
+
+ return currentlyRenderingComponent;
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+
+ return false;
+ }
+
+
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ if (objectIs(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+function createHook() {
+ if (numberOfReRenders > 0) {
+ throw new Error('Rendered more hooks than during the previous render');
+ }
+
+ return {
+ memoizedState: null,
+ queue: null,
+ next: null
+ };
+}
+
+function createWorkInProgressHook() {
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ if (firstWorkInProgressHook === null) {
+ isReRender = false;
+ firstWorkInProgressHook = workInProgressHook = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = firstWorkInProgressHook;
+ }
+ } else {
+ if (workInProgressHook.next === null) {
+ isReRender = false; // Append to the end of the list
+
+ workInProgressHook = workInProgressHook.next = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = workInProgressHook.next;
+ }
+ }
+
+ return workInProgressHook;
+}
+
+function prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState) {
+ currentlyRenderingComponent = componentIdentity;
+ currentlyRenderingTask = task;
+ currentlyRenderingRequest = request;
+ currentlyRenderingKeyPath = keyPath;
+ // didScheduleRenderPhaseUpdate = false;
+ // firstWorkInProgressHook = null;
+ // numberOfReRenders = 0;
+ // renderPhaseUpdates = null;
+ // workInProgressHook = null;
+
+
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ thenableState = prevThenableState;
+}
+function finishHooks(Component, props, children, refOrContext) {
+ // This must be called after every function component to prevent hooks from
+ // being used in classes.
+ while (didScheduleRenderPhaseUpdate) {
+ // Updates were scheduled during the render phase. They are stored in
+ // the `renderPhaseUpdates` map. Call the component again, reusing the
+ // work-in-progress hooks and applying the additional updates on top. Keep
+ // restarting until no more updates are scheduled.
+ didScheduleRenderPhaseUpdate = false;
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ numberOfReRenders += 1; // Start over from the beginning of the list
+
+ workInProgressHook = null;
+ children = Component(props, refOrContext);
+ }
+
+ resetHooksState();
+ return children;
+}
+function getThenableStateAfterSuspending() {
+ const state = thenableState;
+ thenableState = null;
+ return state;
+}
+function checkDidRenderIdHook() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ const didRenderIdHook = localIdCounter !== 0;
+ return didRenderIdHook;
+}
+function getFormStateCount() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateCounter;
+}
+function getFormStateMatchingIndex() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateMatchingIndex;
+} // Reset the internal hooks state if an error occurs while rendering a component
+
+function resetHooksState() {
+
+ currentlyRenderingComponent = null;
+ currentlyRenderingTask = null;
+ currentlyRenderingRequest = null;
+ currentlyRenderingKeyPath = null;
+ didScheduleRenderPhaseUpdate = false;
+ firstWorkInProgressHook = null;
+ numberOfReRenders = 0;
+ renderPhaseUpdates = null;
+ workInProgressHook = null;
+}
+
+function readContext(context) {
+
+ return readContext$1(context);
+}
+
+function useContext(context) {
+
+ resolveCurrentlyRenderingComponent();
+ return readContext$1(context);
+}
+
+function basicStateReducer(state, action) {
+ // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
+ return typeof action === 'function' ? action(state) : action;
+}
+
+function useState(initialState) {
+
+ return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers
+ initialState);
+}
+function useReducer(reducer, initialArg, init) {
+
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+
+ if (isReRender) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ // current hook.
+ const queue = workInProgressHook.queue;
+ const dispatch = queue.dispatch;
+
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate !== undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.delete(queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ let newState = workInProgressHook.memoizedState;
+ let update = firstRenderPhaseUpdate;
+
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ const action = update.action;
+
+ newState = reducer(newState, action);
+
+
+ update = update.next;
+ } while (update !== null); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ workInProgressHook.memoizedState = newState;
+ return [newState, dispatch];
+ }
+ } // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ return [workInProgressHook.memoizedState, dispatch];
+ } else {
+
+ let initialState;
+
+ if (reducer === basicStateReducer) {
+ // Special case for `useState`.
+ initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
+ } else {
+ initialState = init !== undefined ? init(initialArg) : initialArg;
+ }
+
+
+ workInProgressHook.memoizedState = initialState; // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ const queue = workInProgressHook.queue = {
+ last: null,
+ dispatch: null
+ };
+ const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ return [workInProgressHook.memoizedState, dispatch];
+ }
+}
+
+function useMemo(nextCreate, deps) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const nextDeps = deps === undefined ? null : deps;
+
+ if (workInProgressHook !== null) {
+ const prevState = workInProgressHook.memoizedState;
+
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ const prevDeps = prevState[1];
+
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ }
+
+ const nextValue = nextCreate();
+
+
+ workInProgressHook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function useRef(initialValue) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const previousRef = workInProgressHook.memoizedState;
+
+ if (previousRef === null) {
+ const ref = {
+ current: initialValue
+ };
+
+
+ workInProgressHook.memoizedState = ref;
+ return ref;
+ } else {
+ return previousRef;
+ }
+}
+
+function dispatchAction(componentIdentity, queue, action) {
+ if (numberOfReRenders >= RE_RENDER_LIMIT) {
+ throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.');
+ }
+
+ if (componentIdentity === currentlyRenderingComponent) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ const update = {
+ action,
+ next: null
+ };
+
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate === undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+
+ lastRenderPhaseUpdate.next = update;
+ }
+ }
+}
+
+function useCallback(callback, deps) {
+ return useMemo(() => callback, deps);
+}
+
+function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
+ if (getServerSnapshot === undefined) {
+ throw new Error('Missing getServerSnapshot, which is required for ' + 'server-rendered content. Will revert to client rendering.');
+ }
+
+ return getServerSnapshot();
+}
+
+function useDeferredValue(value, initialValue) {
+ resolveCurrentlyRenderingComponent();
+
+ {
+ return value;
+ }
+}
+
+function unsupportedStartTransition() {
+ throw new Error('startTransition cannot be called during server rendering.');
+}
+
+function useTransition() {
+ resolveCurrentlyRenderingComponent();
+ return [false, unsupportedStartTransition];
+}
+
+function useHostTransitionStatus() {
+ resolveCurrentlyRenderingComponent();
+ return NotPendingTransition;
+}
+
+function unsupportedSetOptimisticState() {
+ throw new Error('Cannot update optimistic state while rendering.');
+}
+
+function useOptimistic(passthrough, reducer) {
+ resolveCurrentlyRenderingComponent();
+ return [passthrough, unsupportedSetOptimisticState];
+}
+
+function createPostbackFormStateKey(permalink, componentKeyPath, hookIndex) {
+ if (permalink !== undefined) {
+ // Don't bother to hash a permalink-based key since it's already short.
+ return 'p' + permalink;
+ } else {
+ // Append a node to the key path that represents the form state hook.
+ const keyPath = [componentKeyPath, null, hookIndex]; // Key paths are hashed to reduce the size. It does not need to be secure,
+ // and it's more important that it's fast than that it's completely
+ // collision-free.
+
+ const keyPathHash = createFastHashJS(JSON.stringify(keyPath));
+ return 'k' + keyPathHash;
+ }
+}
+
+function useFormState(action, initialState, permalink) {
+ resolveCurrentlyRenderingComponent(); // Count the number of useFormState hooks per component. We also use this to
+ // track the position of this useFormState hook relative to the other ones in
+ // this component, so we can generate a unique key for each one.
+
+ const formStateHookIndex = formStateCounter++;
+ const request = currentlyRenderingRequest; // $FlowIgnore[prop-missing]
+
+ const formAction = action.$$FORM_ACTION;
+
+ if (typeof formAction === 'function') {
+ // This is a server action. These have additional features to enable
+ // MPA-style form submissions with progressive enhancement.
+ // TODO: If the same permalink is passed to multiple useFormStates, and
+ // they all have the same action signature, Fizz will pass the postback
+ // state to all of them. We should probably only pass it to the first one,
+ // and/or warn.
+ // The key is lazily generated and deduped so the that the keypath doesn't
+ // get JSON.stringify-ed unnecessarily, and at most once.
+ let nextPostbackStateKey = null; // Determine the current form state. If we received state during an MPA form
+ // submission, then we will reuse that, if the action identity matches.
+ // Otherwise we'll use the initial state argument. We will emit a comment
+ // marker into the stream that indicates whether the state was reused.
+
+ let state = initialState;
+ const componentKeyPath = currentlyRenderingKeyPath;
+ const postbackFormState = getFormState(request); // $FlowIgnore[prop-missing]
+
+ const isSignatureEqual = action.$$IS_SIGNATURE_EQUAL;
+
+ if (postbackFormState !== null && typeof isSignatureEqual === 'function') {
+ const postbackKey = postbackFormState[1];
+ const postbackReferenceId = postbackFormState[2];
+ const postbackBoundArity = postbackFormState[3];
+
+ if (isSignatureEqual.call(action, postbackReferenceId, postbackBoundArity)) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+
+ if (postbackKey === nextPostbackStateKey) {
+ // This was a match
+ formStateMatchingIndex = formStateHookIndex; // Reuse the state that was submitted by the form.
+
+ state = postbackFormState[0];
+ }
+ }
+ } // Bind the state to the first argument of the action.
+
+
+ const boundAction = action.bind(null, state); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ }; // $FlowIgnore[prop-missing]
+
+
+ if (typeof boundAction.$$FORM_ACTION === 'function') {
+ // $FlowIgnore[prop-missing]
+ dispatch.$$FORM_ACTION = prefix => {
+ const metadata = boundAction.$$FORM_ACTION(prefix); // Override the action URL
+
+ if (permalink !== undefined) {
+
+ permalink += '';
+ metadata.action = permalink;
+ }
+
+ const formData = metadata.data;
+
+ if (formData) {
+ if (nextPostbackStateKey === null) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+ }
+
+ formData.append('$ACTION_KEY', nextPostbackStateKey);
+ }
+
+ return metadata;
+ };
+ }
+
+ return [state, dispatch];
+ } else {
+ // This is not a server action, so the implementation is much simpler.
+ // Bind the state to the first argument of the action.
+ const boundAction = action.bind(null, initialState); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ };
+
+ return [initialState, dispatch];
+ }
+}
+
+function useId() {
+ const task = currentlyRenderingTask;
+ const treeId = getTreeId(task.treeContext);
+ const resumableState = currentResumableState;
+
+ if (resumableState === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component.');
+ }
+
+ const localId = localIdCounter++;
+ return makeId(resumableState, treeId, localId);
+}
+
+function use(usable) {
+ if (usable !== null && typeof usable === 'object') {
+ // $FlowFixMe[method-unbinding]
+ if (typeof usable.then === 'function') {
+ // This is a thenable.
+ const thenable = usable;
+ return unwrapThenable(thenable);
+ } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = usable;
+ return readContext(context);
+ }
+ } // eslint-disable-next-line react-internal/safe-string-coercion
+
+
+ throw new Error('An unsupported type was passed to use(): ' + String(usable));
+}
+
+function unwrapThenable(thenable) {
+ const index = thenableIndexCounter;
+ thenableIndexCounter += 1;
+
+ if (thenableState === null) {
+ thenableState = createThenableState();
+ }
+
+ return trackUsedThenable(thenableState, thenable, index);
+}
+
+function unsupportedRefresh() {
+ throw new Error('Cache cannot be refreshed during server rendering.');
+}
+
+function useCacheRefresh() {
+ return unsupportedRefresh;
+}
+
+function noop$1() {}
+
+const HooksDispatcher = {
+ readContext,
+ use,
+ useContext,
+ useMemo,
+ useReducer,
+ useRef,
+ useState,
+ useInsertionEffect: noop$1,
+ useLayoutEffect: noop$1,
+ useCallback,
+ // useImperativeHandle is not run in the server environment
+ useImperativeHandle: noop$1,
+ // Effects are not run in the server environment.
+ useEffect: noop$1,
+ // Debugging effect
+ useDebugValue: noop$1,
+ useDeferredValue,
+ useTransition,
+ useId,
+ // Subscriptions are not setup in a server environment.
+ useSyncExternalStore
+};
+
+{
+ HooksDispatcher.useCacheRefresh = useCacheRefresh;
+}
+
+{
+ HooksDispatcher.useHostTransitionStatus = useHostTransitionStatus;
+}
+
+{
+ HooksDispatcher.useOptimistic = useOptimistic;
+ HooksDispatcher.useFormState = useFormState;
+}
+
+let currentResumableState = null;
+function setCurrentResumableState(resumableState) {
+ currentResumableState = resumableState;
+}
+
+function getCacheSignal() {
+ throw new Error('Not implemented.');
+}
+
+function getCacheForType(resourceType) {
+ throw new Error('Not implemented.');
+}
+
+const DefaultCacheDispatcher = {
+ getCacheSignal,
+ getCacheForType
+};
+
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
+const ReactCurrentCache = ReactSharedInternals.ReactCurrentCache;
+// The name might be minified but we assume that it's going to be the same generated name. Typically
+// because it's just the same compiled output in practice.
+// resume with segmentID at the index
+
+const CLIENT_RENDERED = 4; // if it errors or infinitely suspends
+
+const PENDING = 0;
+const COMPLETED = 1;
+const FLUSHED = 2;
+const ABORTED = 3;
+const ERRORED = 4;
+const POSTPONED = 5;
+const OPEN = 0;
+const CLOSING = 1;
+const CLOSED = 2; // This is a default heuristic for how to split up the HTML content into progressive
+// loading. Our goal is to be able to display additional new content about every 500ms.
+// Faster than that is unnecessary and should be throttled on the client. It also
+// adds unnecessary overhead to do more splits. We don't know if it's a higher or lower
+// end device but higher end suffer less from the overhead than lower end does from
+// not getting small enough pieces. We error on the side of low end.
+// We base this on low end 3G speeds which is about 500kbits per second. We assume
+// that there can be a reasonable drop off from max bandwidth which leaves you with
+// as little as 80%. We can receive half of that each 500ms - at best. In practice,
+// a little bandwidth is lost to processing and contention - e.g. CSS and images that
+// are downloaded along with the main content. So we estimate about half of that to be
+// the lower end throughput. In other words, we expect that you can at least show
+// about 12.5kb of content per 500ms. Not counting starting latency for the first
+// paint.
+// 500 * 1024 / 8 * .8 * 0.5 / 2
+
+const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
+
+function defaultErrorHandler(error) {
+ console['error'](error); // Don't transform to our wrapper
+
+ return null;
+}
+
+function noop() {}
+
+function createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, formState) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState,
+ renderState,
+ rootFormatContext,
+ progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: 0,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: formState === undefined ? null : formState
+ }; // This segment represents the root fallback.
+
+ const rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false); // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+let currentRequest = null;
+function resolveRequest() {
+ if (currentRequest) return currentRequest;
+
+ if (supportsRequestStorage) {
+ const store = requestStorage.getStore();
+ if (store) return store;
+ }
+
+ return null;
+}
+
+function pingTask(request, task) {
+ const pingedTasks = request.pingedTasks;
+ pingedTasks.push(task);
+
+ if (request.pingedTasks.length === 1) {
+ request.flushScheduled = request.destination !== null;
+ scheduleWork(() => performWork(request));
+ }
+}
+
+function createSuspenseBoundary(request, fallbackAbortableTasks) {
+ return {
+ status: PENDING,
+ rootSegmentID: -1,
+ parentFlushed: false,
+ pendingTasks: 0,
+ completedSegments: [],
+ byteSize: 0,
+ fallbackAbortableTasks,
+ errorDigest: null,
+ resources: createBoundaryResources(),
+ trackedContentKeyPath: null,
+ trackedFallbackNode: null
+ };
+}
+
+function createRenderTask(request, thenableState, node, childIndex, blockedBoundary, blockedSegment, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ const task = {
+ replay: null,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createReplayTask(request, thenableState, replay, node, childIndex, blockedBoundary, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ replay.pendingTasks++;
+ const task = {
+ replay,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment: null,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createPendingSegment(request, index, boundary, parentFormatContext, lastPushedText, textEmbedded) {
+ return {
+ status: PENDING,
+ id: -1,
+ // lazily assigned later
+ index,
+ parentFlushed: false,
+ chunks: [],
+ children: [],
+ parentFormatContext,
+ boundary,
+ lastPushedText,
+ textEmbedded
+ };
+} // DEV-only global reference to the currently executing task
+
+function popComponentStackInDEV(task) {
+} // stash the component stack of an unwinding error until it is processed
+
+function logRecoverableError(request, error) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ const errorDigest = request.onError(error);
+
+ if (errorDigest != null && typeof errorDigest !== 'string') {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead");
+ }
+
+ return errorDigest;
+}
+
+function fatalError(request, error) {
+ // This is called outside error handling code such as if the root errors outside
+ // a suspense boundary or if the root suspense boundary's fallback errors.
+ // It's also called if React itself or its host configs errors.
+ const onShellError = request.onShellError;
+ onShellError(error);
+ const onFatalError = request.onFatalError;
+ onFatalError(error);
+
+ if (request.destination !== null) {
+ request.status = CLOSED;
+ closeWithError(request.destination, error);
+ } else {
+ request.status = CLOSING;
+ request.fatalError = error;
+ }
+}
+
+function renderSuspenseBoundary(request, someTask, keyPath, props) {
+ if (someTask.replay !== null) {
+ // If we're replaying through this pass, it means we're replaying through
+ // an already completed Suspense boundary. It's too late to do anything about it
+ // so we can just render through it.
+ const prevKeyPath = someTask.keyPath;
+ someTask.keyPath = keyPath;
+ const content = props.children;
+
+ try {
+ renderNode(request, someTask, content, -1);
+ } finally {
+ someTask.keyPath = prevKeyPath;
+ }
+
+ return;
+ } // $FlowFixMe: Refined.
+
+
+ const task = someTask;
+ const prevKeyPath = task.keyPath;
+ const parentBoundary = task.blockedBoundary;
+ const parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for
+ // the fallback so that we can later replace that segment with the content.
+ // This also lets us split out the main content even if it doesn't suspend,
+ // in case it ends up generating a large subtree of content.
+
+ const fallback = props.fallback;
+ const content = props.children;
+ const fallbackAbortSet = new Set();
+ const newBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+
+ if (request.trackedPostpones !== null) {
+ newBoundary.trackedContentKeyPath = keyPath;
+ }
+
+ const insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback.
+
+ const boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false);
+ parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent
+
+ parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately.
+
+ const contentRootSegment = createPendingSegment(request, 0, null, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is
+ // no parent segment so there's nothing to wait on.
+
+ contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks.
+ // I suspect that there might be some efficiency benefits from not creating the suspended task
+ // and instead just using the stack if possible.
+ // TODO: Call this directly instead of messing with saving and restoring contexts.
+ // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and which segment
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = newBoundary;
+ task.blockedSegment = contentRootSegment;
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, newBoundary.resources);
+ }
+
+ task.keyPath = keyPath;
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+ pushSegmentFinale(contentRootSegment.chunks, request.renderState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded);
+ contentRootSegment.status = COMPLETED;
+ queueCompletedSegment(newBoundary, contentRootSegment);
+
+ if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
+ newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ contentRootSegment.status = ERRORED;
+ newBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ newBoundary.errorDigest = errorDigest;
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.blockedSegment = parentSegment;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]];
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones !== null) {
+ // We create a detached replay node to track any postpones inside the fallback.
+ const fallbackReplayNode = [fallbackKeyPath[1], fallbackKeyPath[2], [], null];
+ trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
+
+ if (newBoundary.status === POSTPONED) {
+ // This must exist now.
+ const boundaryReplayNode = trackedPostpones.workingMap.get(keyPath);
+ boundaryReplayNode[4] = fallbackReplayNode;
+ } else {
+ // We might not inject it into the postponed tree, unless the content actually
+ // postpones too. We need to keep track of it until that happpens.
+ newBoundary.trackedFallbackNode = fallbackReplayNode;
+ }
+ } // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+
+ const suspendedFallbackTask = createRenderTask(request, null, fallback, -1, parentBoundary, boundarySegment, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function replaySuspenseBoundary(request, task, keyPath, props, id, childNodes, childSlots, fallbackNodes, fallbackSlots) {
+ const prevKeyPath = task.keyPath;
+ const previousReplaySet = task.replay;
+ const parentBoundary = task.blockedBoundary;
+ const content = props.children;
+ const fallback = props.fallback;
+ const fallbackAbortSet = new Set();
+ const resumedBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = id; // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and replay node
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = resumedBoundary;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, resumedBoundary.resources);
+ }
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+
+ if (resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING) {
+ resumedBoundary.status = COMPLETED;
+ request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ resumedBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ resumedBoundary.errorDigest = errorDigest;
+
+ task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted.
+
+ request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task.
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.replay = previousReplaySet;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+ const fallbackReplay = {
+ nodes: fallbackNodes,
+ slots: fallbackSlots,
+ pendingTasks: 0
+ };
+ const suspendedFallbackTask = createReplayTask(request, null, fallbackReplay, fallback, -1, parentBoundary, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function renderHostElement(request, task, keyPath, type, props) {
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ const children = props.children; // TODO: Make this a Config for replaying.
+
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ } else {
+ // Render
+ const children = pushStartInstance(segment.chunks, type, props, request.resumableState, request.renderState, task.formatContext, segment.lastPushedText);
+ segment.lastPushedText = false;
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ pushEndInstance(segment.chunks, type, props, request.resumableState, prevContext);
+ segment.lastPushedText = false;
+ }
+}
+
+function shouldConstruct(Component) {
+ return Component.prototype && Component.prototype.isReactComponent;
+}
+
+function renderWithHooks(request, task, keyPath, prevThenableState, Component, props, secondArg) {
+ const componentIdentity = {};
+ prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState);
+ const result = Component(props, secondArg);
+ return finishHooks(Component, props, result, secondArg);
+}
+
+function finishClassComponent(request, task, keyPath, instance, Component, props) {
+ const nextChildren = instance.render();
+
+ {
+ const childContextTypes = Component.childContextTypes;
+
+ if (childContextTypes !== null && childContextTypes !== undefined) {
+ const previousContext = task.legacyContext;
+ const mergedContext = processChildContext(instance, Component, previousContext, childContextTypes);
+ task.legacyContext = mergedContext;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.legacyContext = previousContext;
+ return;
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderClassComponent(request, task, keyPath, Component, props) {
+ const maskedContext = getMaskedContext(Component, task.legacyContext) ;
+ const instance = constructClassInstance(Component, props, maskedContext);
+ mountClassInstance(instance, Component, props, maskedContext);
+ finishClassComponent(request, task, keyPath, instance, Component);
+}
+// components for some reason.
+
+function renderIndeterminateComponent(request, task, keyPath, prevThenableState, Component, props) {
+ let legacyContext;
+
+ {
+ legacyContext = getMaskedContext(Component, task.legacyContext);
+ }
+
+ const value = renderWithHooks(request, task, keyPath, prevThenableState, Component, props, legacyContext);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+
+ if ( // Run these checks in production only if the flag is off.
+ // Eventually we'll delete this branch altogether.
+ typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
+
+ mountClassInstance(value, Component, props, legacyContext);
+ finishClassComponent(request, task, keyPath, value, Component);
+ } else {
+
+ finishFunctionComponent(request, task, keyPath, value, hasId, formStateCount, formStateMatchingIndex);
+ }
+}
+
+function finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex) {
+ let didEmitFormStateMarkers = false;
+
+ if (formStateCount !== 0 && request.formState !== null) {
+ // For each useFormState hook, emit a marker that indicates whether we
+ // rendered using the form state passed at the root. We only emit these
+ // markers if form state is passed at the root.
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ didEmitFormStateMarkers = true;
+ const target = segment.chunks;
+
+ for (let i = 0; i < formStateCount; i++) {
+ if (i === formStateMatchingIndex) {
+ pushFormStateMarkerIsMatching(target);
+ } else {
+ pushFormStateMarkerIsNotMatching(target);
+ }
+ }
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+
+ if (hasId) {
+ // This component materialized an id. We treat this as its own level, with
+ // a single "child" slot.
+ const prevTreeContext = task.treeContext;
+ const totalChildren = 1;
+ const index = 0; // Modify the id context. Because we'll need to reset this if something
+ // suspends or errors, we'll use the non-destructive render path.
+
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
+ renderNode(request, task, children, -1); // Like the other contexts, this does not need to be in a finally block
+ // because renderNode takes care of unwinding the stack.
+
+ task.treeContext = prevTreeContext;
+ } else if (didEmitFormStateMarkers) {
+ // If there were formState hooks, we must use the non-destructive path
+ // because this component is not a pure indirection; we emitted markers
+ // to the stream.
+ renderNode(request, task, children, -1);
+ } else {
+ // We're now successfully past this task, and we haven't modified the
+ // context stack. We don't have to pop back to the previous task every
+ // again, so we can use the destructive recursive form.
+ renderNodeDestructive(request, task, null, children, -1);
+ }
+
+ task.keyPath = prevKeyPath;
+}
+
+function resolveDefaultProps(Component, baseProps) {
+ if (Component && Component.defaultProps) {
+ // Resolve default props. Taken from ReactElement
+ const props = assign({}, baseProps);
+ const defaultProps = Component.defaultProps;
+
+ for (const propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+
+ return props;
+ }
+
+ return baseProps;
+}
+
+function renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref) {
+ const children = renderWithHooks(request, task, keyPath, prevThenableState, type.render, props, ref);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+ finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex);
+}
+
+function renderMemo(request, task, keyPath, prevThenableState, type, props, ref) {
+ const innerType = type.type;
+ const resolvedProps = resolveDefaultProps(innerType, props);
+ renderElement(request, task, keyPath, prevThenableState, innerType, resolvedProps, ref);
+}
+
+function renderContextConsumer(request, task, keyPath, context, props) {
+
+ const render = props.children;
+
+ const newValue = readContext$1(context);
+ const newChildren = render(newValue);
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, newChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderContextProvider(request, task, keyPath, type, props) {
+ const context = type._context;
+ const value = props.value;
+ const children = props.children;
+
+ const prevKeyPath = task.keyPath;
+ task.context = pushProvider(context, value);
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, children, -1);
+ task.context = popProvider();
+ task.keyPath = prevKeyPath;
+}
+
+function renderLazyComponent(request, task, keyPath, prevThenableState, lazyComponent, props, ref) {
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+ const Component = init(payload);
+ const resolvedProps = resolveDefaultProps(Component, props);
+ renderElement(request, task, keyPath, prevThenableState, Component, resolvedProps, ref);
+}
+
+function renderOffscreen(request, task, keyPath, props) {
+ const mode = props.mode;
+
+ if (mode === 'hidden') ; else {
+ // A visible Offscreen boundary is treated exactly like a fragment: a
+ // pure indirection.
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ }
+}
+
+function renderElement(request, task, keyPath, prevThenableState, type, props, ref) {
+ if (typeof type === 'function') {
+ if (shouldConstruct(type)) {
+ renderClassComponent(request, task, keyPath, type, props);
+ return;
+ } else {
+ renderIndeterminateComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+
+ if (typeof type === 'string') {
+ renderHostElement(request, task, keyPath, type, props);
+ return;
+ }
+
+ switch (type) {
+ // LegacyHidden acts the same as a fragment. This only works because we
+ // currently assume that every instance of LegacyHidden is accompanied by a
+ // host component wrapper. In the hidden mode, the host component is given a
+ // `hidden` attribute, which ensures that the initial HTML is not visible.
+ // To support the use of LegacyHidden as a true fragment, without an extra
+ // DOM node, we would have to hide the initial HTML in some other way.
+ // TODO: Delete in LegacyHidden. It's an unstable API only used in the
+ // www build. As a migration step, we could add a special prop to Offscreen
+ // that simulates the old behavior (no hiding, no change to effects).
+ case REACT_LEGACY_HIDDEN_TYPE:
+ case REACT_DEBUG_TRACING_MODE_TYPE:
+ case REACT_STRICT_MODE_TYPE:
+ case REACT_PROFILER_TYPE:
+ case REACT_FRAGMENT_TYPE:
+ {
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_OFFSCREEN_TYPE:
+ {
+ renderOffscreen(request, task, keyPath, props);
+ return;
+ }
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ {
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_SCOPE_TYPE:
+ {
+
+ throw new Error('ReactDOMServer does not yet support scope components.');
+ }
+
+ case REACT_SUSPENSE_TYPE:
+ {
+ {
+ renderSuspenseBoundary(request, task, keyPath, props);
+ }
+
+ return;
+ }
+ }
+
+ if (typeof type === 'object' && type !== null) {
+ switch (type.$$typeof) {
+ case REACT_FORWARD_REF_TYPE:
+ {
+ renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_MEMO_TYPE:
+ {
+ renderMemo(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_PROVIDER_TYPE:
+ {
+ renderContextProvider(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_CONTEXT_TYPE:
+ {
+ renderContextConsumer(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_LAZY_TYPE:
+ {
+ renderLazyComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+ }
+
+ let info = '';
+
+ throw new Error('Element type is invalid: expected a string (for built-in ' + 'components) or a class/function (for composite components) ' + ("but got: " + (type == null ? type : typeof type) + "." + info));
+}
+
+function resumeNode(request, task, segmentId, node, childIndex) {
+ const prevReplay = task.replay;
+ const blockedBoundary = task.blockedBoundary;
+ const resumedSegment = createPendingSegment(request, 0, null, task.formatContext, false, false);
+ resumedSegment.id = segmentId;
+ resumedSegment.parentFlushed = true;
+
+ try {
+ // Convert the current ReplayTask to a RenderTask.
+ const renderTask = task;
+ renderTask.replay = null;
+ renderTask.blockedSegment = resumedSegment;
+ renderNode(request, task, node, childIndex);
+ resumedSegment.status = COMPLETED;
+
+ if (blockedBoundary === null) {
+ request.completedRootSegment = resumedSegment;
+ } else {
+ queueCompletedSegment(blockedBoundary, resumedSegment);
+
+ if (blockedBoundary.parentFlushed) {
+ request.partialBoundaries.push(blockedBoundary);
+ }
+ }
+ } finally {
+ // Restore to a ReplayTask.
+ task.replay = prevReplay;
+ task.blockedSegment = null;
+ }
+}
+
+function replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, replay) {
+ // We're replaying. Find the path to follow.
+ const replayNodes = replay.nodes;
+
+ for (let i = 0; i < replayNodes.length; i++) {
+ // Flow doesn't support refinement on tuples so we do it manually here.
+ const node = replayNodes[i];
+
+ if (keyOrIndex !== node[1]) {
+ continue;
+ }
+
+ if (node.length === 4) {
+ // Matched a replayable path.
+ // Let's double check that the component name matches as a precaution.
+ if (name !== null && name !== node[0]) {
+ throw new Error('Expected the resume to render <' + node[0] + '> in this slot but instead it rendered <' + name + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ const currentNode = task.node;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0 // TODO check remaining slots
+ ) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ if (task.node === currentNode) {
+ // This same element suspended so we need to pop the replay we just added.
+ task.replay = replay;
+ }
+
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay;
+ } else {
+ // Let's double check that the component type matches.
+ if (type !== REACT_SUSPENSE_TYPE) {
+ const expectedType = 'Suspense';
+ throw new Error('Expected the resume to render <' + expectedType + '> in this slot but instead it rendered <' + (getComponentNameFromType(type) || 'Unknown') + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ } // Matched a replayable path.
+
+
+ replaySuspenseBoundary(request, task, keyPath, props, node[5], node[2], node[3], node[4] === null ? [] : node[4][2], node[4] === null ? null : node[4][3]);
+ } // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+
+ replayNodes.splice(i, 1);
+ return;
+ } // We didn't find any matching nodes. We assume that this element was already
+ // rendered in the prelude and skip it.
+
+} // $FlowFixMe[missing-local-annot]
+
+function renderNodeDestructive(request, task, // The thenable state reused from the previous attempt, if any. This is almost
+// always null, except when called by retryTask.
+prevThenableState, node, childIndex) {
+ {
+ return renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex);
+ }
+} // This function by it self renders a node and consumes the task by mutating it
+// to update the current execution state.
+
+
+function renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex) {
+ if (task.replay !== null && typeof task.replay.slots === 'number') {
+ // TODO: Figure out a cheaper place than this hot path to do this check.
+ const resumeSegmentID = task.replay.slots;
+ resumeNode(request, task, resumeSegmentID, node, childIndex);
+ return;
+ } // Stash the node we're working on. We'll pick up from this task in case
+ // something suspends.
+
+
+ task.node = node;
+ task.childIndex = childIndex; // Handle object types
+
+ if (typeof node === 'object' && node !== null) {
+ switch (node.$$typeof) {
+ case REACT_ELEMENT_TYPE:
+ {
+ const element = node;
+ const type = element.type;
+ const key = element.key;
+ const props = element.props;
+ const ref = element.ref;
+ const name = getComponentNameFromType(type);
+ const keyOrIndex = key == null ? childIndex === -1 ? 0 : childIndex : key;
+ const keyPath = [task.keyPath, name, keyOrIndex];
+
+ if (task.replay !== null) {
+ replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, task.replay); // No matches found for this node. We assume it's already emitted in the
+ // prelude and skip it during the replay.
+ } else {
+ // We're doing a plain render.
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+ }
+
+ return;
+ }
+
+ case REACT_PORTAL_TYPE:
+ throw new Error('Portals are not currently supported by the server renderer. ' + 'Render them conditionally so that they only appear on the client render.');
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyNode = node;
+ const payload = lazyNode._payload;
+ const init = lazyNode._init;
+ let resolvedNode;
+
+ {
+ resolvedNode = init(payload);
+ }
+
+ renderNodeDestructive(request, task, null, resolvedNode, childIndex);
+ return;
+ }
+ }
+
+ if (isArray(node)) {
+ renderChildrenArray(request, task, node, childIndex);
+ return;
+ }
+
+ const iteratorFn = getIteratorFn(node);
+
+ if (iteratorFn) {
+
+ const iterator = iteratorFn.call(node);
+
+ if (iterator) {
+ // We need to know how many total children are in this set, so that we
+ // can allocate enough id slots to acommodate them. So we must exhaust
+ // the iterator before we start recursively rendering the children.
+ // TODO: This is not great but I think it's inherent to the id
+ // generation algorithm.
+ let step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that.
+
+ if (!step.done) {
+ const children = [];
+
+ do {
+ children.push(step.value);
+ step = iterator.next();
+ } while (!step.done);
+
+ renderChildrenArray(request, task, children, childIndex);
+ return;
+ }
+
+ return;
+ }
+ } // Usables are a valid React node type. When React encounters a Usable in
+ // a child position, it unwraps it using the same algorithm as `use`. For
+ // example, for promises, React will throw an exception to unwind the
+ // stack, then replay the component once the promise resolves.
+ //
+ // A difference from `use` is that React will keep unwrapping the value
+ // until it reaches a non-Usable type.
+ //
+ // e.g. Usable>> should resolve to T
+
+
+ const maybeUsable = node;
+
+ if (typeof maybeUsable.then === 'function') {
+ const thenable = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable), childIndex);
+ }
+
+ if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, readContext$1(context), childIndex);
+ } // $FlowFixMe[method-unbinding]
+
+
+ const childString = Object.prototype.toString.call(node);
+ throw new Error("Objects are not valid as a React child (found: " + (childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString) + "). " + 'If you meant to render a collection of children, use an array ' + 'instead.');
+ }
+
+ if (typeof node === 'string') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+
+ if (typeof node === 'number') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, '' + node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+}
+
+function replayFragment(request, task, children, childIndex) {
+ // If we're supposed follow this array, we'd expect to see a ReplayNode matching
+ // this fragment.
+ const replay = task.replay;
+ const replayNodes = replay.nodes;
+
+ for (let j = 0; j < replayNodes.length; j++) {
+ const node = replayNodes[j];
+
+ if (node[1] !== childIndex) {
+ continue;
+ } // Matched a replayable path.
+
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderChildrenArray(request, task, children, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+ // This is an error, stash the component stack if it is null.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay; // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ replayNodes.splice(j, 1);
+ break;
+ }
+}
+
+function renderChildrenArray(request, task, children, childIndex) {
+ const prevKeyPath = task.keyPath;
+
+ if (childIndex !== -1) {
+ task.keyPath = [task.keyPath, 'Fragment', childIndex];
+
+ if (task.replay !== null) {
+ replayFragment(request, // $FlowFixMe: Refined.
+ task, children, childIndex);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ const prevTreeContext = task.treeContext;
+ const totalChildren = children.length;
+
+ if (task.replay !== null) {
+ // Replay
+ // First we need to check if we have any resume slots at this level.
+ const resumeSlots = task.replay.slots;
+
+ if (resumeSlots !== null && typeof resumeSlots === 'object') {
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ const resumeSegmentID = resumeSlots[i]; // TODO: If this errors we should still continue with the next sibling.
+
+ if (typeof resumeSegmentID === 'number') {
+ resumeNode(request, task, resumeSegmentID, node, i); // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ delete resumeSlots[i];
+ } else {
+ renderNode(request, task, node, i);
+ }
+ }
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ renderNode(request, task, node, i);
+ } // Because this context is always set right before rendering every child, we
+ // only need to reset it to the previous value at the very end.
+
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+}
+
+function spawnNewSuspendedReplayTask(request, task, thenableState, x) {
+ const newTask = createReplayTask(request, thenableState, task.replay, task.node, task.childIndex, task.blockedBoundary, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+}
+
+function spawnNewSuspendedRenderTask(request, task, thenableState, x) {
+ // Something suspended, we'll need to create a new segment and resolve it later.
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ const newTask = createRenderTask(request, thenableState, task.node, task.childIndex, task.blockedBoundary, newSegment, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+} // This is a non-destructive form of rendering a node. If it suspends it spawns
+// a new task and restores the context of this task to what it was before.
+
+
+function renderNode(request, task, node, childIndex) {
+ // Snapshot the current context in case something throws to interrupt the
+ // process.
+ const previousFormatContext = task.formatContext;
+ const previousLegacyContext = task.legacyContext;
+ const previousContext = task.context;
+ const previousKeyPath = task.keyPath;
+ const previousTreeContext = task.treeContext;
+
+ let x; // Store how much we've pushed at this point so we can reset it in case something
+ // suspended partially through writing something.
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState();
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedReplayTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode.
+
+ }
+ } else {
+ // Render
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedRenderTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ }
+ }
+ } // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ // Let's terminate the rest of the tree and don't render any siblings.
+
+
+ throw x;
+}
+
+function erroredReplay(request, boundary, error, replayNodes, resumeSlots) {
+ // Erroring during a replay doesn't actually cause an error by itself because
+ // that component has already rendered. What causes the error is the resumable
+ // points that we did not yet finish which will be below the point of the reset.
+ // For example, if we're replaying a path to a Suspense boundary that is not done
+ // that doesn't error the parent Suspense boundary.
+ // This might be a bit strange that the error in a parent gets thrown at a child.
+ // We log it only once and reuse the digest.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ abortRemainingReplayNodes(request, boundary, replayNodes, resumeSlots, error, errorDigest);
+}
+
+function erroredTask(request, boundary, error) {
+ // Report the error to a global handler.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ if (boundary === null) {
+ fatalError(request, error);
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+ // so we can flush it, if the parent already flushed.
+
+
+ if (boundary.parentFlushed) {
+ // We don't have a preference where in the queue this goes since it's likely
+ // to error on the client anyway. However, intentionally client-rendered
+ // boundaries should be flushed earlier so that they can start on the client.
+ // We reuse the same queue for errors.
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function abortTaskSoft(task) {
+ // This aborts task without aborting the parent boundary that it blocks.
+ // It's used for when we didn't need this task to complete the tree.
+ // If task was needed, then it should use abortTask instead.
+ const request = this;
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ finishedTask(request, boundary, segment);
+ }
+}
+
+function abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest) {
+ const resumedBoundary = createSuspenseBoundary(request, new Set());
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = rootSegmentID;
+ resumedBoundary.status = CLIENT_RENDERED;
+ resumedBoundary.errorDigest = errorDigest;
+
+ if (resumedBoundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(resumedBoundary);
+ }
+}
+
+function abortRemainingReplayNodes(request, boundary, nodes, slots, error, errorDigest) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+
+ if (node.length === 4) {
+ abortRemainingReplayNodes(request, boundary, node[2], node[3], error, errorDigest);
+ } else {
+ const boundaryNode = node;
+ const rootSegmentID = boundaryNode[5];
+ abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest);
+ }
+ } // Empty the set, since we've cleared it now.
+
+
+ nodes.length = 0;
+
+ if (slots !== null) {
+ // We had something still to resume in the parent boundary. We must trigger
+ // the error on the parent boundary since it's not able to complete.
+ if (boundary === null) {
+ throw new Error('We should not have any resumable nodes in the shell. ' + 'This is a bug in React.');
+ } else if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // Empty the set
+
+
+ if (typeof slots === 'object') {
+ for (const index in slots) {
+ delete slots[index];
+ }
+ }
+ }
+}
+
+function abortTask(task, request, error) {
+ // This aborts the task and aborts the parent that it blocks, putting it into
+ // client rendered mode.
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ }
+
+ if (boundary === null) {
+ if (request.status !== CLOSING && request.status !== CLOSED) {
+ const replay = task.replay;
+
+ if (replay === null) {
+ // We didn't complete the root so we have nothing to show. We can close
+ // the request;
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ return;
+ } else {
+ // If the shell aborts during a replay, that's not a fatal error. Instead
+ // we should be able to recover by client rendering all the root boundaries in
+ // the ReplaySet.
+ replay.pendingTasks--;
+
+ if (replay.pendingTasks === 0 && replay.nodes.length > 0) {
+ const errorDigest = logRecoverableError(request, error);
+ abortRemainingReplayNodes(request, null, replay.nodes, replay.slots, error, errorDigest);
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ }
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = logRecoverableError(request, error);
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // If this boundary was still pending then we haven't already cancelled its fallbacks.
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
+
+
+ boundary.fallbackAbortableTasks.forEach(fallbackTask => abortTask(fallbackTask, request, error));
+ boundary.fallbackAbortableTasks.clear();
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeShell(request) {
+ if (request.trackedPostpones === null) {
+ // We only emit early preloads on shell completion for renders. For prerenders
+ // we wait for the entire Request to finish because we are not responding to a
+ // live request and can wait for as much data as possible.
+ // we should only be calling completeShell when the shell is complete so we
+ // just use a literal here
+ const shellComplete = true;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ } // We have completed the shell so the shell can't error anymore.
+
+
+ request.onShellError = noop;
+ const onShellReady = request.onShellReady;
+ onShellReady();
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeAll(request) {
+ // During a render the shell must be complete if the entire request is finished
+ // however during a Prerender it is possible that the shell is incomplete because
+ // it postponed. We cannot use rootPendingTasks in the prerender case because
+ // those hit zero even when the shell postpones. Instead we look at the completedRootSegment
+ const shellComplete = request.trackedPostpones === null ? // Render, we assume it is completed
+ true : // Prerender Request, we use the state of the root segment
+ request.completedRootSegment === null || request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ const onAllReady = request.onAllReady;
+ onAllReady();
+}
+
+function queueCompletedSegment(boundary, segment) {
+ if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) {
+ // This is an empty segment. There's nothing to write, so we can instead transfer the ID
+ // to the child. That way any existing references point to the child.
+ const childSegment = segment.children[0];
+ childSegment.id = segment.id;
+ childSegment.parentFlushed = true;
+
+ if (childSegment.status === COMPLETED) {
+ queueCompletedSegment(boundary, childSegment);
+ }
+ } else {
+ const completedSegments = boundary.completedSegments;
+ completedSegments.push(segment);
+ }
+}
+
+function finishedTask(request, boundary, segment) {
+ if (boundary === null) {
+ if (segment !== null && segment.parentFlushed) {
+ if (request.completedRootSegment !== null) {
+ throw new Error('There can only be one root segment. This is a bug in React.');
+ }
+
+ request.completedRootSegment = segment;
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status === CLIENT_RENDERED) ; else if (boundary.pendingTasks === 0) {
+ if (boundary.status === PENDING) {
+ boundary.status = COMPLETED;
+ } // This must have been the last segment we were waiting on. This boundary is now complete.
+
+
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent segment already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ }
+ }
+
+ if (boundary.parentFlushed) {
+ // The segment might be part of a segment that didn't flush yet, but if the boundary's
+ // parent flushed, we need to schedule the boundary to be emitted.
+ request.completedBoundaries.push(boundary);
+ } // We can now cancel any pending task on the fallback since we won't need to show it anymore.
+ // This needs to happen after we read the parentFlushed flags because aborting can finish
+ // work which can trigger user code, which can start flushing, which can change those flags.
+ // If the boundary was POSTPONED, we still need to finish the fallback first.
+
+
+ if (boundary.status === COMPLETED) {
+ boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
+ boundary.fallbackAbortableTasks.clear();
+ }
+ } else {
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length === 1) {
+ // This is the first time since we last flushed that we completed anything.
+ // We can schedule this boundary to emit its partially completed segments early
+ // in case the parent has already been flushed.
+ if (boundary.parentFlushed) {
+ request.partialBoundaries.push(boundary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function retryTask(request, task) {
+ {
+ const blockedBoundary = task.blockedBoundary;
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, blockedBoundary ? blockedBoundary.resources : null);
+ }
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ retryReplayTask(request, // $FlowFixMe: Refined.
+ task);
+ } else {
+ retryRenderTask(request, // $FlowFixMe: Refined.
+ task, segment);
+ }
+}
+
+function retryRenderTask(request, task, segment) {
+ if (segment.status !== PENDING) {
+ // We completed this by other means before we had a chance to retry it.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+ pushSegmentFinale(segment.chunks, request.renderState, segment.lastPushedText, segment.textEmbedded);
+ task.abortSet.delete(task);
+ segment.status = COMPLETED;
+ finishedTask(request, task.blockedBoundary, segment);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.abortSet.delete(task);
+ segment.status = ERRORED;
+ erroredTask(request, task.blockedBoundary, x);
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function retryReplayTask(request, task) {
+ if (task.replay.pendingTasks === 0) {
+ // There are no pending tasks working on this set, so we must have aborted.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ finishedTask(request, task.blockedBoundary, null);
+ } catch (thrownValue) {
+ resetHooksState();
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ erroredReplay(request, task.blockedBoundary, x, task.replay.nodes, task.replay.slots);
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function performWork(request) {
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ const prevContext = getActiveContext();
+ const prevDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = HooksDispatcher;
+ let prevCacheDispatcher;
+
+ {
+ prevCacheDispatcher = ReactCurrentCache.current;
+ ReactCurrentCache.current = DefaultCacheDispatcher;
+ }
+
+ const prevRequest = currentRequest;
+ currentRequest = request;
+
+ const prevResumableState = currentResumableState;
+ setCurrentResumableState(request.resumableState);
+
+ try {
+ const pingedTasks = request.pingedTasks;
+ let i;
+
+ for (i = 0; i < pingedTasks.length; i++) {
+ const task = pingedTasks[i];
+ retryTask(request, task);
+ }
+
+ pingedTasks.splice(0, i);
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ } finally {
+ setCurrentResumableState(prevResumableState);
+ ReactCurrentDispatcher.current = prevDispatcher;
+
+ {
+ ReactCurrentCache.current = prevCacheDispatcher;
+ }
+
+ if (prevDispatcher === HooksDispatcher) {
+ // This means that we were in a reentrant work loop. This could happen
+ // in a renderer that supports synchronous work like renderToString,
+ // when it's called from within another renderer.
+ // Normally we don't bother switching the contexts to their root/default
+ // values when leaving because we'll likely need the same or similar
+ // context again. However, when we're inside a synchronous loop like this
+ // we'll to restore the context to what it was before returning.
+ switchContext(prevContext);
+ }
+
+ currentRequest = prevRequest;
+ }
+}
+
+function flushSubtree(request, destination, segment) {
+ segment.parentFlushed = true;
+
+ switch (segment.status) {
+ case PENDING:
+ {
+ // We're emitting a placeholder for this segment to be filled in later.
+ // Therefore we'll need to assign it an ID - to refer to it by.
+ segment.id = request.nextSegmentId++; // Fallthrough
+ }
+
+ case POSTPONED:
+ {
+ const segmentID = segment.id; // When this segment finally completes it won't be embedded in text since it will flush separately
+
+ segment.lastPushedText = false;
+ segment.textEmbedded = false;
+ return writePlaceholder(destination, request.renderState, segmentID);
+ }
+
+ case COMPLETED:
+ {
+ segment.status = FLUSHED;
+ let r = true;
+ const chunks = segment.chunks;
+ let chunkIdx = 0;
+ const children = segment.children;
+
+ for (let childIdx = 0; childIdx < children.length; childIdx++) {
+ const nextChild = children[childIdx]; // Write all the chunks up until the next child.
+
+ for (; chunkIdx < nextChild.index; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ r = flushSegment(request, destination, nextChild);
+ } // Finally just write all the remaining chunks
+
+
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ if (chunkIdx < chunks.length) {
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
+ }
+
+ return r;
+ }
+
+ default:
+ {
+ throw new Error('Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.');
+ }
+ }
+}
+
+function flushSegment(request, destination, segment) {
+ const boundary = segment.boundary;
+
+ if (boundary === null) {
+ // Not a suspense boundary.
+ return flushSubtree(request, destination, segment);
+ }
+
+ boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to
+ // emit the content or the fallback now.
+
+ if (boundary.status === CLIENT_RENDERED) {
+ // Emit a client rendered suspense boundary wrapper.
+ // We never queue the inner boundary so we'll never emit its content or partial segments.
+ writeStartClientRenderedSuspenseBoundary(destination, request.renderState, boundary.errorDigest); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndClientRenderedSuspenseBoundary(destination);
+ } else if (boundary.status !== COMPLETED) {
+ if (boundary.status === PENDING) {
+ // For pending boundaries we lazily assign an ID to the boundary
+ // and root segment.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ }
+
+ if (boundary.completedSegments.length > 0) {
+ // If this is at least partially complete, we can queue it to be partially emitted early.
+ request.partialBoundaries.push(boundary);
+ } // This boundary is still loading. Emit a pending suspense boundary wrapper.
+
+
+ const id = boundary.rootSegmentID;
+ writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else if (boundary.byteSize > request.progressiveChunkSize) {
+ // This boundary is large and will be emitted separately so that we can progressively show
+ // other content. We add it to the queue during the flush because we have to ensure that
+ // the parent flushes first so that there's something to inject it into.
+ // We also have to make sure that it's emitted into the queue in a deterministic slot.
+ // I.e. we can't insert it here when it completes.
+ // Assign an ID to refer to the future content by.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper.
+
+ writeStartPendingSuspenseBoundary(destination, request.renderState, boundary.rootSegmentID); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else {
+ {
+ hoistResources(request.renderState, boundary.resources);
+ } // We can inline this boundary's content as a complete boundary.
+
+
+ writeStartCompletedSuspenseBoundary(destination);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length !== 1) {
+ throw new Error('A previously unvisited boundary must have exactly one root segment. This is a bug in React.');
+ }
+
+ const contentSegment = completedSegments[0];
+ flushSegment(request, destination, contentSegment);
+ return writeEndCompletedSuspenseBoundary(destination);
+ }
+}
+
+function flushClientRenderedBoundary(request, destination, boundary) {
+ return writeClientRenderBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack);
+}
+
+function flushSegmentContainer(request, destination, segment) {
+ writeStartSegment(destination, request.renderState, segment.parentFormatContext, segment.id);
+ flushSegment(request, destination, segment);
+ return writeEndSegment(destination, segment.parentFormatContext);
+}
+
+function flushCompletedBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+ flushPartiallyCompletedSegment(request, destination, boundary, segment);
+ }
+
+ completedSegments.length = 0;
+
+ {
+ writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+
+ return writeCompletedBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.resources);
+}
+
+function flushPartialBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+
+ if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) {
+ i++;
+ completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority
+ // might want to write later.
+
+ return false;
+ }
+ }
+
+ completedSegments.splice(0, i);
+
+ {
+ // The way this is structured we only write resources for partial boundaries
+ // if there is no backpressure. Later before we complete the boundary we
+ // will write resources regardless of backpressure before we emit the
+ // completion instruction
+ return writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+}
+
+function flushPartiallyCompletedSegment(request, destination, boundary, segment) {
+ if (segment.status === FLUSHED) {
+ // We've already flushed this inline.
+ return true;
+ }
+
+ const segmentID = segment.id;
+
+ if (segmentID === -1) {
+ // This segment wasn't previously referred to. This happens at the root of
+ // a boundary. We make kind of a leap here and assume this is the root.
+ const rootSegmentID = segment.id = boundary.rootSegmentID;
+
+ if (rootSegmentID === -1) {
+ throw new Error('A root segment ID must have been assigned by now. This is a bug in React.');
+ }
+
+ return flushSegmentContainer(request, destination, segment);
+ } else if (segmentID === boundary.rootSegmentID) {
+ // When we emit postponed boundaries, we might have assigned the ID already
+ // but it's still the root segment so we can't inject it into the parent yet.
+ return flushSegmentContainer(request, destination, segment);
+ } else {
+ flushSegmentContainer(request, destination, segment);
+ return writeCompletedSegmentInstruction(destination, request.resumableState, request.renderState, segmentID);
+ }
+}
+
+function flushCompletedQueues(request, destination) {
+ beginWriting();
+
+ try {
+ // The structure of this is to go through each queue one by one and write
+ // until the sink tells us to stop. When we should stop, we still finish writing
+ // that item fully and then yield. At that point we remove the already completed
+ // items up until the point we completed them.
+ let i;
+ const completedRootSegment = request.completedRootSegment;
+
+ if (completedRootSegment !== null) {
+ if (completedRootSegment.status === POSTPONED) {
+ // We postponed the root, so we write nothing.
+ return;
+ } else if (request.pendingRootTasks === 0) {
+ if (enableFloat) {
+ writePreamble(destination, request.resumableState, request.renderState, request.allPendingTasks === 0 && request.trackedPostpones === null);
+ }
+
+ flushSegment(request, destination, completedRootSegment);
+ request.completedRootSegment = null;
+ writeCompletedRoot(destination, request.renderState, request.resumableState);
+ } else {
+ // We haven't flushed the root yet so we don't need to check any other branches further down
+ return;
+ }
+ }
+
+ if (enableFloat) {
+ writeHoistables(destination, request.resumableState, request.renderState);
+ } // We emit client rendering instructions for already emitted boundaries first.
+ // This is so that we can signal to the client to start client rendering them as
+ // soon as possible.
+
+
+ const clientRenderedBoundaries = request.clientRenderedBoundaries;
+
+ for (i = 0; i < clientRenderedBoundaries.length; i++) {
+ const boundary = clientRenderedBoundaries[i];
+
+ if (!flushClientRenderedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ clientRenderedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries
+ // that are completely done since we can actually show them, than it is to emit
+ // any individual segments from a partially complete boundary.
+
+ const completedBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < completedBoundaries.length; i++) {
+ const boundary = completedBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ completedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before
+ // we continue with lower priorities.
+
+ completeWriting(destination);
+ beginWriting(destination); // TODO: Here we'll emit data used by hydration.
+ // Next we emit any segments of any boundaries that are partially complete
+ // but not deeply complete.
+
+ const partialBoundaries = request.partialBoundaries;
+
+ for (i = 0; i < partialBoundaries.length; i++) {
+ const boundary = partialBoundaries[i];
+
+ if (!flushPartialBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ partialBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had
+ // boundaries added to it in case they were too larged to be inlined.
+ // New ones might be added in this loop.
+
+ const largeBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < largeBoundaries.length; i++) {
+ const boundary = largeBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ largeBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ largeBoundaries.splice(0, i);
+ } finally {
+ if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because
+ // either they have pending task or they're complete.
+ ) {
+ request.flushScheduled = false;
+
+ {
+ // We write the trailing tags but only if don't have any data to resume.
+ // If we need to resume we'll write the postamble in the resume instead.
+ {
+ writePostamble(destination, request.resumableState);
+ }
+ }
+
+ completeWriting(destination);
+
+
+ close(destination); // We need to stop flowing now because we do not want any async contexts which might call
+ // float methods to initiate any flushes after this point
+
+ stopFlowing(request);
+ } else {
+ completeWriting(destination);
+ }
+ }
+}
+
+function startWork(request) {
+ request.flushScheduled = request.destination !== null;
+
+ if (supportsRequestStorage) {
+ scheduleWork(() => requestStorage.run(request, performWork, request));
+ } else {
+ scheduleWork(() => performWork(request));
+ }
+
+ if (request.trackedPostpones === null) {
+ // this is either a regular render or a resume. For regular render we want
+ // to call emitEarlyPreloads after the first performWork because we want
+ // are responding to a live request and need to balance sending something early
+ // (i.e. don't want for the shell to finish) but we need something to send.
+ // The only implementation of this is for DOM at the moment and during resumes nothing
+ // actually emits but the code paths here are the same.
+ // During a prerender we don't want to be too aggressive in emitting early preloads
+ // because we aren't responding to a live request and we can wait for the prerender to
+ // postpone before we emit anything.
+ if (supportsRequestStorage) {
+ scheduleWork(() => requestStorage.run(request, enqueueEarlyPreloadsAfterInitialWork, request));
+ } else {
+ scheduleWork(() => enqueueEarlyPreloadsAfterInitialWork(request));
+ }
+ }
+}
+
+function enqueueEarlyPreloadsAfterInitialWork(request) {
+ const shellComplete = request.pendingRootTasks === 0;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+
+function enqueueFlush(request) {
+ if (request.flushScheduled === false && // If there are pinged tasks we are going to flush anyway after work completes
+ request.pingedTasks.length === 0 && // If there is no destination there is nothing we can flush to. A flush will
+ // happen when we start flowing again
+ request.destination !== null) {
+ request.flushScheduled = true;
+ scheduleWork(() => {
+ // We need to existence check destination again here because it might go away
+ // in between the enqueueFlush call and the work execution
+ const destination = request.destination;
+
+ if (destination) {
+ flushCompletedQueues(request, destination);
+ } else {
+ request.flushScheduled = false;
+ }
+ });
+ }
+} // This function is intented to only be called during the pipe function for the Node builds.
+function startFlowing(request, destination) {
+ if (request.status === CLOSING) {
+ request.status = CLOSED;
+ closeWithError(destination, request.fatalError);
+ return;
+ }
+
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ if (request.destination !== null) {
+ // We're already flowing.
+ return;
+ }
+
+ request.destination = destination;
+
+ try {
+ flushCompletedQueues(request, destination);
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function stopFlowing(request) {
+ request.destination = null;
+} // This is called to early terminate a request. It puts all pending boundaries in client rendered state.
+
+function abort(request, reason) {
+ try {
+ const abortableTasks = request.abortableTasks;
+
+ if (abortableTasks.size > 0) {
+ const error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason;
+ abortableTasks.forEach(task => abortTask(task, request, error));
+ abortableTasks.clear();
+ }
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function flushResources(request) {
+ enqueueFlush(request);
+}
+function getFormState(request) {
+ return request.formState;
+}
+function getResumableState(request) {
+ return request.resumableState;
+}
+function getRenderState(request) {
+ return request.renderState;
+}
+
+function renderToReadableStream(children, options) {
+ return new Promise((resolve, reject) => {
+ let onFatalError;
+ let onAllReady;
+ const allReady = new Promise((res, rej) => {
+ onAllReady = res;
+ onFatalError = rej;
+ });
+
+ function onShellReady() {
+ const stream = new ReadableStream({
+ type: 'bytes',
+ pull: controller => {
+ startFlowing(request, controller);
+ },
+ cancel: reason => {
+ stopFlowing(request);
+ abort(request, reason);
+ }
+ }, // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
+ {
+ highWaterMark: 0
+ }); // TODO: Move to sub-classing ReadableStream.
+
+ stream.allReady = allReady;
+ resolve(stream);
+ }
+
+ function onShellError(error) {
+ // If the shell errors the caller of `renderToReadableStream` won't have access to `allReady`.
+ // However, `allReady` will be rejected by `onFatalError` as well.
+ // So we need to catch the duplicate, uncatchable fatal error in `allReady` to prevent a `UnhandledPromiseRejection`.
+ allReady.catch(() => {});
+ reject(error);
+ }
+
+ const onHeaders = options ? options.onHeaders : undefined;
+ let onHeadersImpl;
+
+ if (onHeaders) {
+ onHeadersImpl = headersDescriptor => {
+ onHeaders(new Headers(headersDescriptor));
+ };
+ }
+
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ const request = createRequest(children, resumableState, createRenderState(resumableState, options ? options.nonce : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, onHeadersImpl, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, onAllReady, onShellReady, onShellError, onFatalError, options ? options.onPostpone : undefined, options ? options.formState : undefined);
+
+ if (options && options.signal) {
+ const signal = options.signal;
+
+ if (signal.aborted) {
+ abort(request, signal.reason);
+ } else {
+ const listener = () => {
+ abort(request, signal.reason);
+ signal.removeEventListener('abort', listener);
+ };
+
+ signal.addEventListener('abort', listener);
+ }
+ }
+
+ startWork(request);
+ });
+}
+
+exports.renderToReadableStream = renderToReadableStream;
+exports.version = ReactVersion;
\ No newline at end of file
diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.min.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.min.js
index 19b765a7a057a..770c2990ed1d3 100644
--- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.min.js
+++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.min.js
@@ -1,13 +1,11 @@
-/**
- * @license React
- * react-dom-server.edge.production.min.js
- *
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
/*
+ React
+ react-dom-server.edge.production.min.js
+
+ Copyright (c) Meta Platforms, Inc. and affiliates.
+
+ This source code is licensed under the MIT license found in the
+ LICENSE file in the root directory of this source tree.
JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
@@ -34,7 +32,7 @@
'use strict';var aa=require("next/dist/compiled/react"),ca=require("react-dom");
function da(a,b){var c=a.length&3;var d=a.length-c;var e=b;for(b=0;b>>16)&65535)<<16)&4294967295;f=f<<15|f>>>17;f=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295;e^=f;e=e<<13|e>>>19;e=5*(e&65535)+((5*(e>>>16)&65535)<<16)&4294967295;e=(e&65535)+27492+(((e>>>16)+58964&65535)<<16)}f=0;switch(c){case 3:f^=(a.charCodeAt(b+2)&255)<<
16;case 2:f^=(a.charCodeAt(b+1)&255)<<8;case 1:f^=a.charCodeAt(b)&255,f=3432918353*(f&65535)+((3432918353*(f>>>16)&65535)<<16)&4294967295,f=f<<15|f>>>17,e^=461845907*(f&65535)+((461845907*(f>>>16)&65535)<<16)&4294967295}e^=a.length;e^=e>>>16;e=2246822507*(e&65535)+((2246822507*(e>>>16)&65535)<<16)&4294967295;e^=e>>>13;e=3266489909*(e&65535)+((3266489909*(e>>>16)&65535)<<16)&4294967295;return(e^e>>>16)>>>0}var k=null,m=0;
-function r(a,b){if(0!==b.byteLength)if(512 '),ob=x("');
+const startScriptSrc = stringToPrecomputedChunk('');
+/**
+ * This escaping function is designed to work with bootstrapScriptContent and importMap only.
+ * because we know we are escaping the entire script. We can avoid for instance
+ * escaping html comment string sequences that are valid javascript as well because
+ * if there are no sebsequent '); // Since we store headers as strings we deal with their length in utf16 code units
+// rather than visual characters or the utf8 encoding that is used for most binary
+// serialization. Some common HTTP servers only allow for headers to be 4kB in length.
+// We choose a default length that is likely to be well under this already limited length however
+// pathological cases may still cause the utf-8 encoding of the headers to approach this limit.
+// It should also be noted that this maximum is a soft maximum. we have not reached the limit we will
+// allow one more header to be captured which means in practice if the limit is approached it will be exceeded
+
+const DEFAULT_HEADERS_CAPACITY_IN_UTF16_CODE_UNITS = 2000; // Allows us to keep track of what we've already written so we can refer back to it.
+// if passed externalRuntimeConfig and the enableFizzExternalRuntime feature flag
+// is set, the server will send instructions via data attributes (instead of inline scripts)
+
+function createRenderState(resumableState, nonce, externalRuntimeConfig, importMap, onHeaders, maxHeadersLength) {
+ const inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('');
+const completeSegmentData1 = stringToPrecomputedChunk('');
+const completeBoundaryData1 = stringToPrecomputedChunk('');
+const clientRenderData1 = stringToPrecomputedChunk('
+ return writeChunkAndReturn(destination, clientRenderDataEnd);
+ }
+}
+const regexForJSStringsInInstructionScripts = /[<\u2028\u2029]/g;
+
+function escapeJSStringsForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInInstructionScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const regexForJSStringsInScripts = /[&><\u2028\u2029]/g;
+
+function escapeJSObjectForInstructionScripts(input) {
+ const escaped = JSON.stringify(input);
+ return escaped.replace(regexForJSStringsInScripts, match => {
+ switch (match) {
+ // santizing breaking out of strings and script tags
+ case '&':
+ return '\\u0026';
+
+ case '>':
+ return '\\u003e';
+
+ case '<':
+ return '\\u003c';
+
+ case '\u2028':
+ return '\\u2028';
+
+ case '\u2029':
+ return '\\u2029';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeJSObjectForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+ });
+}
+
+const lateStyleTagResourceOpen1 = stringToPrecomputedChunk(''); // Tracks whether the boundary currently flushing is flushign style tags or has any
+// stylesheet dependencies not flushed in the Preamble.
+
+let currentlyRenderingBoundaryHasStylesToHoist = false; // Acts as a return value for the forEach execution of style tag flushing.
+
+let destinationHasCapacity = true;
+
+function flushStyleTagsLateForBoundary(styleQueue) {
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs;
+
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, lateStyleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ writeChunk(this, lateStyleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, lateStyleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ destinationHasCapacity = writeChunkAndReturn(this, lateStyleTagTemplateClose); // We wrote style tags for this boundary and we may need to emit a script
+ // to hoist them.
+
+ currentlyRenderingBoundaryHasStylesToHoist = true; // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function hasStylesToHoist(stylesheet) {
+ // We need to reveal boundaries with styles whenever a stylesheet it depends on is either
+ // not flushed or flushed after the preamble (shell).
+ if (stylesheet.state !== PREAMBLE) {
+ currentlyRenderingBoundaryHasStylesToHoist = true;
+ return true;
+ }
+
+ return false;
+}
+
+function writeResourcesForBoundary(destination, boundaryResources, renderState) {
+ // Reset these on each invocation, they are only safe to read in this function
+ currentlyRenderingBoundaryHasStylesToHoist = false;
+ destinationHasCapacity = true; // Flush style tags for each precedence this boundary depends on
+
+ boundaryResources.styles.forEach(flushStyleTagsLateForBoundary, destination); // Determine if this boundary has stylesheets that need to be awaited upon completion
+
+ boundaryResources.stylesheets.forEach(hasStylesToHoist);
+
+ if (currentlyRenderingBoundaryHasStylesToHoist) {
+ renderState.stylesToHoist = true;
+ }
+
+ return destinationHasCapacity;
+}
+
+function flushResource(resource) {
+ for (let i = 0; i < resource.length; i++) {
+ writeChunk(this, resource[i]);
+ }
+
+ resource.length = 0;
+}
+
+const stylesheetFlushingQueue = [];
+
+function flushStyleInPreamble(stylesheet, key, map) {
+ // We still need to encode stylesheet chunks
+ // because unlike most Hoistables and Resources we do not eagerly encode
+ // them during render. This is because if we flush late we have to send a
+ // different encoding and we don't want to encode multiple times
+ pushLinkImpl(stylesheetFlushingQueue, stylesheet.props);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ stylesheet.state = PREAMBLE;
+}
+
+const styleTagResourceOpen1 = stringToPrecomputedChunk('');
+
+function flushStylesInPreamble(styleQueue, precedence) {
+ const hasStylesheets = styleQueue.sheets.size > 0;
+ styleQueue.sheets.forEach(flushStyleInPreamble, this);
+ styleQueue.sheets.clear();
+ const rules = styleQueue.rules;
+ const hrefs = styleQueue.hrefs; // If we don't emit any stylesheets at this precedence we still need to maintain the precedence
+ // order so even if there are no rules for style tags at this precedence we emit an empty style
+ // tag with the data-precedence attribute
+
+ if (!hasStylesheets || hrefs.length) {
+ writeChunk(this, styleTagResourceOpen1);
+ writeChunk(this, styleQueue.precedence);
+ let i = 0;
+
+ if (hrefs.length) {
+ writeChunk(this, styleTagResourceOpen2);
+
+ for (; i < hrefs.length - 1; i++) {
+ writeChunk(this, hrefs[i]);
+ writeChunk(this, spaceSeparator);
+ }
+
+ writeChunk(this, hrefs[i]);
+ }
+
+ writeChunk(this, styleTagResourceOpen3);
+
+ for (i = 0; i < rules.length; i++) {
+ writeChunk(this, rules[i]);
+ }
+
+ writeChunk(this, styleTagResourceClose); // style resources can flush continuously since more rules may be written into
+ // them with new hrefs. Instead of marking it flushed, we simply reset the chunks
+ // and hrefs
+
+ rules.length = 0;
+ hrefs.length = 0;
+ }
+}
+
+function preloadLateStyle(stylesheet) {
+ if (stylesheet.state === PENDING$1) {
+ stylesheet.state = PRELOADED;
+ const preloadProps = preloadAsStylePropsFromProps(stylesheet.props.href, stylesheet.props);
+ pushLinkImpl(stylesheetFlushingQueue, preloadProps);
+
+ for (let i = 0; i < stylesheetFlushingQueue.length; i++) {
+ writeChunk(this, stylesheetFlushingQueue[i]);
+ }
+
+ stylesheetFlushingQueue.length = 0;
+ }
+}
+
+function preloadLateStyles(styleQueue) {
+ styleQueue.sheets.forEach(preloadLateStyle, this);
+ styleQueue.sheets.clear();
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+
+function writePreamble(destination, resumableState, renderState, willFlushAllSegments) {
+ // This function must be called exactly once on every request
+ if (!willFlushAllSegments && renderState.externalRuntimeScript) {
+ // If the root segment is incomplete due to suspended tasks
+ // (e.g. willFlushAllSegments = false) and we are using data
+ // streaming format, ensure the external runtime is sent.
+ // (User code could choose to send this even earlier by calling
+ // preinit(...), if they know they will suspend).
+ const _renderState$external = renderState.externalRuntimeScript,
+ src = _renderState$external.src,
+ chunks = _renderState$external.chunks;
+ internalPreinitScript(resumableState, renderState, src, chunks);
+ }
+
+ const htmlChunks = renderState.htmlChunks;
+ const headChunks = renderState.headChunks;
+ let i = 0; // Emit open tags before Hoistables and Resources
+
+ if (htmlChunks) {
+ // We have an to emit as part of the preamble
+ for (i = 0; i < htmlChunks.length; i++) {
+ writeChunk(destination, htmlChunks[i]);
+ }
+
+ if (headChunks) {
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } else {
+ // We did not render a head but we emitted an so we emit one now
+ writeChunk(destination, startChunkForTag('head'));
+ writeChunk(destination, endOfStartTag);
+ }
+ } else if (headChunks) {
+ // We do not have an but we do have a
+ for (i = 0; i < headChunks.length; i++) {
+ writeChunk(destination, headChunks[i]);
+ }
+ } // Emit high priority Hoistables
+
+
+ const charsetChunks = renderState.charsetChunks;
+
+ for (i = 0; i < charsetChunks.length; i++) {
+ writeChunk(destination, charsetChunks[i]);
+ }
+
+ charsetChunks.length = 0; // emit preconnect resources
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Flush unblocked stylesheets by precedence
+
+ renderState.styles.forEach(flushStylesInPreamble, destination);
+ const importMapChunks = renderState.importMapChunks;
+
+ for (i = 0; i < importMapChunks.length; i++) {
+ writeChunk(destination, importMapChunks[i]);
+ }
+
+ importMapChunks.length = 0;
+ renderState.bootstrapScripts.forEach(flushResource, destination);
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0; // Flush closing head if necessary
+
+ if (htmlChunks && headChunks === null) {
+ // We have an rendered but no rendered. We however inserted
+ // a up above so we need to emit the now. This is safe because
+ // if the main content contained the it would also have provided a
+ // . This means that all the content inside is either or
+ // invalid HTML
+ writeChunk(destination, endChunkForTag('head'));
+ }
+} // We don't bother reporting backpressure at the moment because we expect to
+// flush the entire preamble in a single pass. This probably should be modified
+// in the future to be backpressure sensitive but that requires a larger refactor
+// of the flushing code in Fizz.
+
+function writeHoistables(destination, resumableState, renderState) {
+ let i = 0; // Emit high priority Hoistables
+ // We omit charsetChunks because we have already sent the shell and if it wasn't
+ // already sent it is too late now.
+
+ renderState.preconnects.forEach(flushResource, destination);
+ renderState.preconnects.clear();
+ const preconnectChunks = renderState.preconnectChunks;
+
+ for (i = 0; i < preconnectChunks.length; i++) {
+ writeChunk(destination, preconnectChunks[i]);
+ }
+
+ preconnectChunks.length = 0;
+ renderState.fontPreloads.forEach(flushResource, destination);
+ renderState.fontPreloads.clear();
+ renderState.highImagePreloads.forEach(flushResource, destination);
+ renderState.highImagePreloads.clear(); // Preload any stylesheets. these will emit in a render instruction that follows this
+ // but we want to kick off preloading as soon as possible
+
+ renderState.styles.forEach(preloadLateStyles, destination); // We only hoist importmaps that are configured through createResponse and that will
+ // always flush in the preamble. Generally we don't expect people to render them as
+ // tags when using React but if you do they are going to be treated like regular inline
+ // scripts and flush after other hoistables which is problematic
+ // bootstrap scripts should flush above script priority but these can only flush in the preamble
+ // so we elide the code here for performance
+
+ renderState.scripts.forEach(flushResource, destination);
+ renderState.scripts.clear();
+ renderState.bulkPreloads.forEach(flushResource, destination);
+ renderState.bulkPreloads.clear(); // Write embedding preloadChunks
+
+ const preloadChunks = renderState.preloadChunks;
+
+ for (i = 0; i < preloadChunks.length; i++) {
+ writeChunk(destination, preloadChunks[i]);
+ }
+
+ preloadChunks.length = 0; // Write embedding hoistableChunks
+
+ const hoistableChunks = renderState.hoistableChunks;
+
+ for (i = 0; i < hoistableChunks.length; i++) {
+ writeChunk(destination, hoistableChunks[i]);
+ }
+
+ hoistableChunks.length = 0;
+}
+function writePostamble(destination, resumableState) {
+ if (resumableState.hasBody) {
+ writeChunk(destination, endChunkForTag('body'));
+ }
+
+ if (resumableState.hasHtml) {
+ writeChunk(destination, endChunkForTag('html'));
+ }
+}
+const arrayFirstOpenBracket = stringToPrecomputedChunk('[');
+const arraySubsequentOpenBracket = stringToPrecomputedChunk(',[');
+const arrayInterstitial = stringToPrecomputedChunk(',');
+const arrayCloseBracket = stringToPrecomputedChunk(']'); // This function writes a 2D array of strings to be embedded in javascript.
+// E.g.
+// [["JS_escaped_string1", "JS_escaped_string2"]]
+
+function writeStyleResourceDependenciesInJS(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInJS(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInJS(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInJS(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+}
+
+function writeStyleResourceDependencyInJS(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedHref)));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(coercedPrecedence)));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInJS(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInJS(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeName)));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeJSObjectForInstructionScripts(attributeValue)));
+} // This function writes a 2D array of strings to be embedded in an attribute
+// value and read with JSON.parse in ReactDOMServerExternalRuntime.js
+// E.g.
+// [["JSON_escaped_string1", "JSON_escaped_string2"]]
+
+
+function writeStyleResourceDependenciesInAttr(destination, boundaryResources) {
+ writeChunk(destination, arrayFirstOpenBracket);
+ let nextArrayOpenBrackChunk = arrayFirstOpenBracket;
+ boundaryResources.stylesheets.forEach(resource => {
+ if (resource.state === PREAMBLE) ; else if (resource.state === LATE) {
+ // We only need to emit the href because this resource flushed in an earlier
+ // boundary already which encoded the attributes necessary to construct
+ // the resource instance on the client.
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyHrefOnlyInAttr(destination, resource.props.href);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ } else {
+ // We need to emit the whole resource for insertion on the client
+ writeChunk(destination, nextArrayOpenBrackChunk);
+ writeStyleResourceDependencyInAttr(destination, resource.props.href, resource.props['data-precedence'], resource.props);
+ writeChunk(destination, arrayCloseBracket);
+ nextArrayOpenBrackChunk = arraySubsequentOpenBracket;
+ resource.state = LATE;
+ }
+ });
+ writeChunk(destination, arrayCloseBracket);
+}
+/* Helper functions */
+
+
+function writeStyleResourceDependencyHrefOnlyInAttr(destination, href) {
+
+ const coercedHref = '' + href;
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+}
+
+function writeStyleResourceDependencyInAttr(destination, href, precedence, props) {
+ // eslint-disable-next-line react-internal/safe-string-coercion
+ const coercedHref = sanitizeURL('' + href);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedHref))));
+
+ const coercedPrecedence = '' + precedence;
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(coercedPrecedence))));
+
+ for (const propKey in props) {
+ if (hasOwnProperty.call(props, propKey)) {
+ const propValue = props[propKey];
+
+ if (propValue == null) {
+ continue;
+ }
+
+ switch (propKey) {
+ case 'href':
+ case 'rel':
+ case 'precedence':
+ case 'data-precedence':
+ {
+ break;
+ }
+
+ case 'children':
+ case 'dangerouslySetInnerHTML':
+ throw new Error('link' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.');
+
+ default:
+ writeStyleResourceAttributeInAttr(destination, propKey, propValue);
+ break;
+ }
+ }
+ }
+
+ return null;
+}
+
+function writeStyleResourceAttributeInAttr(destination, name, value) // not null or undefined
+{
+ let attributeName = name.toLowerCase();
+ let attributeValue;
+
+ switch (typeof value) {
+ case 'function':
+ case 'symbol':
+ return;
+ }
+
+ switch (name) {
+ // Reserved names
+ case 'innerHTML':
+ case 'dangerouslySetInnerHTML':
+ case 'suppressContentEditableWarning':
+ case 'suppressHydrationWarning':
+ case 'style':
+ // Ignored
+ return;
+ // Attribute renames
+
+ case 'className':
+ {
+ attributeName = 'class';
+
+ attributeValue = '' + value;
+ break;
+ }
+ // Booleans
+
+ case 'hidden':
+ {
+ if (value === false) {
+ return;
+ }
+
+ attributeValue = '';
+ break;
+ }
+ // Santized URLs
+
+ case 'src':
+ case 'href':
+ {
+ value = sanitizeURL(value);
+
+ attributeValue = '' + value;
+ break;
+ }
+
+ default:
+ {
+ if ( // unrecognized event handlers are not SSR'd and we (apparently)
+ // use on* as hueristic for these handler props
+ name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
+ return;
+ }
+
+ if (!isAttributeNameSafe(name)) {
+ return;
+ }
+
+ attributeValue = '' + value;
+ }
+ }
+
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeName))));
+ writeChunk(destination, arrayInterstitial);
+ writeChunk(destination, stringToChunk(escapeTextForBrowser(JSON.stringify(attributeValue))));
+}
+/**
+ * Resources
+ */
+
+
+const PENDING$1 = 0;
+const PRELOADED = 1;
+const PREAMBLE = 2;
+const LATE = 3;
+function createBoundaryResources() {
+ return {
+ styles: new Set(),
+ stylesheets: new Set()
+ };
+}
+function setCurrentlyRenderingBoundaryResourcesTarget(renderState, boundaryResources) {
+ renderState.boundaryResources = boundaryResources;
+}
+
+function getResourceKey(href) {
+ return href;
+}
+
+function getImageResourceKey(href, imageSrcSet, imageSizes) {
+ if (imageSrcSet) {
+ return imageSrcSet + '\n' + (imageSizes || '');
+ }
+
+ return href;
+}
+
+function prefetchDNS(href) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const key = getResourceKey(href);
+
+ if (!resumableState.dnsResources.hasOwnProperty(key)) {
+ resumableState.dnsResources[key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPrefetchDNSAsHeader(href), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this as resettable in case we are prerendering and postpone in the Shell
+ renderState.resets.dns[key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ // Encode as element
+ const resource = [];
+ pushLinkImpl(resource, {
+ href,
+ rel: 'dns-prefetch'
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preconnect(href, crossOrigin) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (typeof href === 'string' && href) {
+ const bucket = crossOrigin === 'use-credentials' ? 'credentials' : typeof crossOrigin === 'string' ? 'anonymous' : 'default';
+ const key = getResourceKey(href);
+
+ if (!resumableState.connectResources[bucket].hasOwnProperty(key)) {
+ resumableState.connectResources[bucket][key] = EXISTS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreconnectAsHeader(href, crossOrigin), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // Store this in resettableState in case we are prerending and postpone in the Shell
+ renderState.resets.connect[bucket][key] = EXISTS;
+
+ if (headers.preconnects) {
+ headers.preconnects += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.preconnects += header;
+ } else {
+ const resource = [];
+ pushLinkImpl(resource, {
+ rel: 'preconnect',
+ href,
+ crossOrigin
+ });
+ renderState.preconnects.add(resource);
+ }
+ }
+
+ flushResources(request);
+ }
+}
+
+function preload(href, as, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (as && href) {
+ switch (as) {
+ case 'image':
+ {
+ let imageSrcSet, imageSizes, fetchPriority;
+
+ if (options) {
+ imageSrcSet = options.imageSrcSet;
+ imageSizes = options.imageSizes;
+ fetchPriority = options.fetchPriority;
+ }
+
+ const key = getImageResourceKey(href, imageSrcSet, imageSizes);
+
+ if (resumableState.imageResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resumableState.imageResources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && fetchPriority === 'high' && ( // Compute the header since we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit a preload as a header so we
+ // track this to make sure we don't reset it.
+ renderState.resets.image[key] = PRELOAD_NO_CREDS;
+
+ if (headers.highImagePreloads) {
+ headers.highImagePreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.highImagePreloads += header;
+ } else {
+ // If we don't have headers to write to we have to encode as elements to flush in the head
+ // When we have imageSrcSet the browser probably cannot load the right version from headers
+ // (this should be verified by testing). For now we assume these need to go in the head
+ // as elements even if headers are available.
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ // There is a bug in Safari where imageSrcSet is not respected on preload links
+ // so we omit the href here if we have imageSrcSet b/c safari will load the wrong image.
+ // This harms older browers that do not support imageSrcSet by making their preloads not work
+ // but this population is shrinking fast and is already small so we accept this tradeoff.
+ href: imageSrcSet ? undefined : href,
+ as
+ }, options));
+
+ if (fetchPriority === 'high') {
+ renderState.highImagePreloads.add(resource);
+ } else {
+ renderState.bulkPreloads.add(resource); // Stash the resource in case we need to promote it to higher priority
+ // when an img tag is rendered
+
+ renderState.preloads.images.set(key, resource);
+ }
+ }
+
+ break;
+ }
+
+ case 'style':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.styleResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.styleResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.stylesheets.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ break;
+ }
+
+ case 'script':
+ {
+ const key = getResourceKey(href);
+
+ if (resumableState.scriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ const resource = [];
+ renderState.preloads.scripts.set(key, resource);
+ renderState.bulkPreloads.add(resource);
+ pushLinkImpl(resource, assign({
+ rel: 'preload',
+ href,
+ as
+ }, options));
+ resumableState.scriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ break;
+ }
+
+ default:
+ {
+ const key = getResourceKey(href);
+ const hasAsType = resumableState.unknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.unknownResources[as] = resources;
+ }
+
+ resources[key] = PRELOAD_NO_CREDS;
+ const headers = renderState.headers;
+ let header;
+
+ if (headers && headers.remainingCapacity > 0 && as === 'font' && ( // We compute the header here because we might be able to fit it in the max length
+ header = getPreloadAsHeader(href, as, options), // We always consume the header length since once we find one header that doesn't fit
+ // we assume all the rest won't as well. This is to avoid getting into a situation
+ // where we have a very small remaining capacity but no headers will ever fit and we end
+ // up constantly trying to see if the next resource might make it. In the future we can
+ // make this behavior different between render and prerender since in the latter case
+ // we are less sensitive to the current requests runtime per and more sensitive to maximizing
+ // headers.
+ (headers.remainingCapacity -= header.length) >= 2)) {
+ // If we postpone in the shell we will still emit this preload so we
+ // track it here to prevent it from being reset.
+ renderState.resets.font[key] = PRELOAD_NO_CREDS;
+
+ if (headers.fontPreloads) {
+ headers.fontPreloads += ', ';
+ } // $FlowFixMe[unsafe-addition]: we assign header during the if condition
+
+
+ headers.fontPreloads += header;
+ } else {
+ // We either don't have headers or we are preloading something that does
+ // not warrant elevated priority so we encode as an element.
+ const resource = [];
+
+ const props = assign({
+ rel: 'preload',
+ href,
+ as
+ }, options);
+
+ pushLinkImpl(resource, props);
+
+ switch (as) {
+ case 'font':
+ renderState.fontPreloads.add(resource);
+ break;
+ // intentional fall through
+
+ default:
+ renderState.bulkPreloads.add(resource);
+ }
+ }
+ }
+ } // If we got this far we created a new resource
+
+
+ flushResources(request);
+ }
+}
+
+function preloadModule(href, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ const key = getResourceKey(href);
+ const as = options && typeof options.as === 'string' ? options.as : 'script';
+ let resource;
+
+ switch (as) {
+ case 'script':
+ {
+ if (resumableState.moduleScriptResources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+
+ resource = [];
+ resumableState.moduleScriptResources[key] = options && (typeof options.crossOrigin === 'string' || typeof options.integrity === 'string') ? [options.crossOrigin, options.integrity] : PRELOAD_NO_CREDS;
+ renderState.preloads.moduleScripts.set(key, resource);
+ break;
+ }
+
+ default:
+ {
+ const hasAsType = resumableState.moduleUnknownResources.hasOwnProperty(as);
+ let resources;
+
+ if (hasAsType) {
+ resources = resumableState.unknownResources[as];
+
+ if (resources.hasOwnProperty(key)) {
+ // we can return if we already have this resource
+ return;
+ }
+ } else {
+ resources = {};
+ resumableState.moduleUnknownResources[as] = resources;
+ }
+
+ resource = [];
+ resources[key] = PRELOAD_NO_CREDS;
+ }
+ }
+
+ pushLinkImpl(resource, assign({
+ rel: 'modulepreload',
+ href
+ }, options));
+ renderState.bulkPreloads.add(resource); // If we got this far we created a new resource
+
+ flushResources(request);
+ }
+}
+
+function preinitStyle(href, precedence, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (href) {
+ precedence = precedence || 'default';
+ const key = getResourceKey(href);
+ let styleQueue = renderState.styles.get(precedence);
+ const hasKey = resumableState.styleResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.styleResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.styleResources[key] = EXISTS; // If this is the first time we've encountered this precedence we need
+ // to create a StyleQueue
+
+ if (!styleQueue) {
+ styleQueue = {
+ precedence: stringToChunk(escapeTextForBrowser(precedence)),
+ rules: [],
+ hrefs: [],
+ sheets: new Map()
+ };
+ renderState.styles.set(precedence, styleQueue);
+ }
+
+ const resource = {
+ state: PENDING$1,
+ props: assign({
+ rel: 'stylesheet',
+ href,
+ 'data-precedence': precedence
+ }, options)
+ };
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(resource.props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.stylesheets.get(key);
+
+ if (preloadResource && preloadResource.length > 0) {
+ // The Preload for this resource was created in this render pass and has not flushed yet so
+ // we need to clear it to avoid it flushing.
+ preloadResource.length = 0;
+ } else {
+ // Either the preload resource from this render already flushed in this render pass
+ // or the preload flushed in a prior pass (prerender). In either case we need to mark
+ // this resource as already having been preloaded.
+ resource.state = PRELOADED;
+ }
+ } // We add the newly created resource to our StyleQueue and if necessary
+ // track the resource with the currently rendering boundary
+
+
+ styleQueue.sheets.set(key, resource); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+ }
+}
+
+function preinitScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.scriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.scriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.scriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.scripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+}
+
+function preinitModuleScript(src, options) {
+
+ const request = resolveRequest();
+
+ if (!request) {
+ // In async contexts we can sometimes resolve resources from AsyncLocalStorage. If we can't we can also
+ // possibly get them from the stack if we are not in an async context. Since we were not able to resolve
+ // the resources for this call in either case we opt to do nothing. We can consider making this a warning
+ // but there may be times where calling a function outside of render is intentional (i.e. to warm up data
+ // fetching) and we don't want to warn in those cases.
+ return;
+ }
+
+ const resumableState = getResumableState(request);
+ const renderState = getRenderState(request);
+
+ if (src) {
+ const key = getResourceKey(src);
+ const hasKey = resumableState.moduleScriptResources.hasOwnProperty(key);
+ const resourceState = hasKey ? resumableState.moduleScriptResources[key] : undefined;
+
+ if (resourceState !== EXISTS) {
+ // We are going to create this resource now so it is marked as Exists
+ resumableState.moduleScriptResources[key] = EXISTS;
+
+ const props = assign({
+ src,
+ type: 'module',
+ async: true
+ }, options);
+
+ if (resourceState) {
+ // When resourceState is truty it is a Preload state. We cast it for clarity
+ const preloadState = resourceState;
+
+ if (preloadState.length === 2) {
+ adoptPreloadCredentials(props, preloadState);
+ }
+
+ const preloadResource = renderState.preloads.moduleScripts.get(key);
+
+ if (preloadResource) {
+ // the preload resource exists was created in this render. Now that we have
+ // a script resource which will emit earlier than a preload would if it
+ // hasn't already flushed we prevent it from flushing by zeroing the length
+ preloadResource.length = 0;
+ }
+ }
+
+ const resource = []; // Add to the script flushing queue
+
+ renderState.scripts.add(resource); // encode the tag as Chunks
+
+ pushScriptImpl(resource, props); // Notify the request that there are resources to flush even if no work is currently happening
+
+ flushResources(request);
+ }
+
+ return;
+ }
+} // This function is only safe to call at Request start time since it assumes
+// that each module has not already been preloaded. If we find a need to preload
+// scripts at any other point in time we will need to check whether the preload
+// already exists and not assume it
+
+
+function preloadBootstrapScriptOrModule(resumableState, renderState, href, props) {
+
+ const key = getResourceKey(href);
+ // used to preinit the resource. If a script can be preinited then it shouldn't
+ // be a bootstrap script/module and if it is a bootstrap script/module then it
+ // must not be safe to emit early. To avoid possibly allowing for preinits of
+ // bootstrap scripts/modules we occlude these keys.
+
+
+ resumableState.scriptResources[key] = EXISTS;
+ resumableState.moduleScriptResources[key] = EXISTS;
+ const resource = [];
+ pushLinkImpl(resource, props);
+ renderState.bootstrapScripts.add(resource);
+}
+
+function internalPreinitScript(resumableState, renderState, src, chunks) {
+ const key = getResourceKey(src);
+
+ if (!resumableState.scriptResources.hasOwnProperty(key)) {
+ const resource = chunks;
+ resumableState.scriptResources[key] = EXISTS;
+ renderState.scripts.add(resource);
+ }
+
+ return;
+}
+
+function preloadAsStylePropsFromProps(href, props) {
+ return {
+ rel: 'preload',
+ as: 'style',
+ href: href,
+ crossOrigin: props.crossOrigin,
+ fetchPriority: props.fetchPriority,
+ integrity: props.integrity,
+ media: props.media,
+ hrefLang: props.hrefLang,
+ referrerPolicy: props.referrerPolicy
+ };
+}
+
+function stylesheetPropsFromRawProps(rawProps) {
+ return assign({}, rawProps, {
+ 'data-precedence': rawProps.precedence,
+ precedence: null
+ });
+}
+
+function adoptPreloadCredentials(target, preloadState) {
+ if (target.crossOrigin == null) target.crossOrigin = preloadState[0];
+ if (target.integrity == null) target.integrity = preloadState[1];
+}
+
+function getPrefetchDNSAsHeader(href) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ return "<" + escapedHref + ">; rel=dns-prefetch";
+}
+
+function getPreconnectAsHeader(href, crossOrigin) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ let value = "<" + escapedHref + ">; rel=preconnect";
+
+ if (typeof crossOrigin === 'string') {
+ const escapedCrossOrigin = escapeStringForLinkHeaderQuotedParamValueContext(crossOrigin);
+ value += "; crossorigin=\"" + escapedCrossOrigin + "\"";
+ }
+
+ return value;
+}
+
+function getPreloadAsHeader(href, as, params) {
+ const escapedHref = escapeHrefForLinkHeaderURLContext(href);
+ const escapedAs = escapeStringForLinkHeaderQuotedParamValueContext(as);
+ let value = "<" + escapedHref + ">; rel=preload; as=\"" + escapedAs + "\"";
+
+ for (const paramName in params) {
+ if (hasOwnProperty.call(params, paramName)) {
+ const paramValue = params[paramName];
+
+ if (typeof paramValue === 'string') {
+ value += "; " + paramName.toLowerCase() + "=\"" + escapeStringForLinkHeaderQuotedParamValueContext(paramValue) + "\"";
+ }
+ }
+ }
+
+ return value;
+}
+
+function getStylesheetPreloadAsHeader(stylesheet) {
+ const props = stylesheet.props;
+ const preloadOptions = {
+ crossOrigin: props.crossOrigin,
+ integrity: props.integrity,
+ nonce: props.nonce,
+ type: props.type,
+ fetchPriority: props.fetchPriority,
+ referrerPolicy: props.referrerPolicy,
+ media: props.media
+ };
+ return getPreloadAsHeader(props.href, 'style', preloadOptions);
+} // This escaping function is only safe to use for href values being written into
+// a "Link" header in between `<` and `>` characters. The primary concern with the href is
+// to escape the bounding characters as well as new lines. This is unsafe to use in any other
+// context
+
+
+const regexForHrefInLinkHeaderURLContext = /[<>\r\n]/g;
+
+function escapeHrefForLinkHeaderURLContext(hrefInput) {
+
+ const coercedHref = '' + hrefInput;
+ return coercedHref.replace(regexForHrefInLinkHeaderURLContext, escapeHrefForLinkHeaderURLContextReplacer);
+}
+
+function escapeHrefForLinkHeaderURLContextReplacer(match) {
+ switch (match) {
+ case '<':
+ return '%3C';
+
+ case '>':
+ return '%3E';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeLinkHrefForHeaderContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+} // This escaping function is only safe to use for quoted param values in an HTTP header.
+// It is unsafe to use for any value not inside quote marks in parater value position.
+
+
+const regexForLinkHeaderQuotedParamValueContext = /["';,\r\n]/g;
+
+function escapeStringForLinkHeaderQuotedParamValueContext(value, name) {
+
+ const coerced = '' + value;
+ return coerced.replace(regexForLinkHeaderQuotedParamValueContext, escapeStringForLinkHeaderQuotedParamValueContextReplacer);
+}
+
+function escapeStringForLinkHeaderQuotedParamValueContextReplacer(match) {
+ switch (match) {
+ case '"':
+ return '%22';
+
+ case "'":
+ return '%27';
+
+ case ';':
+ return '%3B';
+
+ case ',':
+ return '%2C';
+
+ case '\n':
+ return '%0A';
+
+ case '\r':
+ return '%0D';
+
+ default:
+ {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error('escapeStringForLinkHeaderQuotedParamValueContextReplacer encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React');
+ }
+ }
+}
+
+function hoistStyleQueueDependency(styleQueue) {
+ this.styles.add(styleQueue);
+}
+
+function hoistStylesheetDependency(stylesheet) {
+ this.stylesheets.add(stylesheet);
+}
+
+function hoistResources(renderState, source) {
+ const currentBoundaryResources = renderState.boundaryResources;
+
+ if (currentBoundaryResources) {
+ source.styles.forEach(hoistStyleQueueDependency, currentBoundaryResources);
+ source.stylesheets.forEach(hoistStylesheetDependency, currentBoundaryResources);
+ }
+} // This function is called at various times depending on whether we are rendering
+// or prerendering. In this implementation we only actually emit headers once and
+// subsequent calls are ignored. We track whether the request has a completed shell
+// to determine whether we will follow headers with a flush including stylesheets.
+// In the context of prerrender we don't have a completed shell when the request finishes
+// with a postpone in the shell. In the context of a render we don't have a completed shell
+// if this is called before the shell finishes rendering which usually will happen anytime
+// anything suspends in the shell.
+
+function emitEarlyPreloads(renderState, resumableState, shellComplete) {
+ const onHeaders = renderState.onHeaders;
+
+ if (onHeaders) {
+ const headers = renderState.headers;
+
+ if (headers) {
+ let linkHeader = headers.preconnects;
+
+ if (headers.fontPreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.fontPreloads;
+ }
+
+ if (headers.highImagePreloads) {
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += headers.highImagePreloads;
+ }
+
+ if (!shellComplete) {
+ // We use raw iterators because we want to be able to halt iteration
+ // We could refactor renderState to store these dually in arrays to
+ // make this more efficient at the cost of additional memory and
+ // write overhead. However this code only runs once per request so
+ // for now I consider this sufficient.
+ const queueIter = renderState.styles.values();
+
+ outer: for (let queueStep = queueIter.next(); headers.remainingCapacity > 0 && !queueStep.done; queueStep = queueIter.next()) {
+ const sheets = queueStep.value.sheets;
+ const sheetIter = sheets.values();
+
+ for (let sheetStep = sheetIter.next(); headers.remainingCapacity > 0 && !sheetStep.done; sheetStep = sheetIter.next()) {
+ const sheet = sheetStep.value;
+ const props = sheet.props;
+ const key = getResourceKey(props.href);
+ const header = getStylesheetPreloadAsHeader(sheet); // We mutate the capacity b/c we don't want to keep checking if later headers will fit.
+ // This means that a particularly long header might close out the header queue where later
+ // headers could still fit. We could in the future alter the behavior here based on prerender vs render
+ // since during prerender we aren't as concerned with pure runtime performance.
+
+ if ((headers.remainingCapacity -= header.length) >= 2) {
+ renderState.resets.style[key] = PRELOAD_NO_CREDS;
+
+ if (linkHeader) {
+ linkHeader += ', ';
+ }
+
+ linkHeader += header; // We already track that the resource exists in resumableState however
+ // if the resumableState resets because we postponed in the shell
+ // which is what is happening in this branch if we are prerendering
+ // then we will end up resetting the resumableState. When it resets we
+ // want to record the fact that this stylesheet was already preloaded
+
+ renderState.resets.style[key] = typeof props.crossOrigin === 'string' || typeof props.integrity === 'string' ? [props.crossOrigin, props.integrity] : PRELOAD_NO_CREDS;
+ } else {
+ break outer;
+ }
+ }
+ }
+ }
+
+ if (linkHeader) {
+ onHeaders({
+ Link: linkHeader
+ });
+ } else {
+ // We still call this with no headers because a user may be using it as a signal that
+ // it React will not provide any headers
+ onHeaders({});
+ }
+
+ renderState.headers = null;
+ return;
+ }
+ }
+}
+const NotPendingTransition = NotPending;
+
+const requestStorage = new async_hooks.AsyncLocalStorage();
+
+// ATTENTION
+// When adding new symbols to this file,
+// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
+// The Symbol used to tag the ReactElement-like types.
+const REACT_ELEMENT_TYPE = Symbol.for('react.element');
+const REACT_PORTAL_TYPE = Symbol.for('react.portal');
+const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
+const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
+const REACT_PROFILER_TYPE = Symbol.for('react.profiler');
+const REACT_PROVIDER_TYPE = Symbol.for('react.provider');
+const REACT_CONTEXT_TYPE = Symbol.for('react.context');
+const REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
+const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
+const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
+const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
+const REACT_MEMO_TYPE = Symbol.for('react.memo');
+const REACT_LAZY_TYPE = Symbol.for('react.lazy');
+const REACT_SCOPE_TYPE = Symbol.for('react.scope');
+const REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');
+const REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
+const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');
+const REACT_CACHE_TYPE = Symbol.for('react.cache');
+const REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value');
+const MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
+const FAUX_ITERATOR_SYMBOL = '@@iterator';
+function getIteratorFn(maybeIterable) {
+ if (maybeIterable === null || typeof maybeIterable !== 'object') {
+ return null;
+ }
+
+ const maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
+
+ if (typeof maybeIterator === 'function') {
+ return maybeIterator;
+ }
+
+ return null;
+}
+
+function getWrappedName(outerType, innerType, wrapperName) {
+ const displayName = outerType.displayName;
+
+ if (displayName) {
+ return displayName;
+ }
+
+ const functionName = innerType.displayName || innerType.name || '';
+ return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName;
+} // Keep in sync with react-reconciler/getComponentNameFromFiber
+
+
+function getContextName(type) {
+ return type.displayName || 'Context';
+} // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+
+
+function getComponentNameFromType(type) {
+ if (type == null) {
+ // Host root, text node or just invalid type.
+ return null;
+ }
+
+ if (typeof type === 'function') {
+ return type.displayName || type.name || null;
+ }
+
+ if (typeof type === 'string') {
+ return type;
+ }
+
+ switch (type) {
+ case REACT_FRAGMENT_TYPE:
+ return 'Fragment';
+
+ case REACT_PORTAL_TYPE:
+ return 'Portal';
+
+ case REACT_PROFILER_TYPE:
+ return 'Profiler';
+
+ case REACT_STRICT_MODE_TYPE:
+ return 'StrictMode';
+
+ case REACT_SUSPENSE_TYPE:
+ return 'Suspense';
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ return 'SuspenseList';
+
+ case REACT_CACHE_TYPE:
+ {
+ return 'Cache';
+ }
+
+ }
+
+ if (typeof type === 'object') {
+ switch (type.$$typeof) {
+ case REACT_CONTEXT_TYPE:
+ const context = type;
+ return getContextName(context) + '.Consumer';
+
+ case REACT_PROVIDER_TYPE:
+ const provider = type;
+ return getContextName(provider._context) + '.Provider';
+
+ case REACT_FORWARD_REF_TYPE:
+ return getWrappedName(type, type.render, 'ForwardRef');
+
+ case REACT_MEMO_TYPE:
+ const outerName = type.displayName || null;
+
+ if (outerName !== null) {
+ return outerName;
+ }
+
+ return getComponentNameFromType(type.type) || 'Memo';
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyComponent = type;
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+
+ try {
+ return getComponentNameFromType(init(payload));
+ } catch (x) {
+ return null;
+ }
+ }
+
+ }
+ }
+
+ return null;
+}
+
+const emptyContextObject = {};
+
+function getMaskedContext(type, unmaskedContext) {
+ {
+ const contextTypes = type.contextTypes;
+
+ if (!contextTypes) {
+ return emptyContextObject;
+ }
+
+ const context = {};
+
+ for (const key in contextTypes) {
+ context[key] = unmaskedContext[key];
+ }
+
+ return context;
+ }
+}
+function processChildContext(instance, type, parentContext, childContextTypes) {
+ {
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
+ if (typeof instance.getChildContext !== 'function') {
+
+ return parentContext;
+ }
+
+ const childContext = instance.getChildContext();
+
+ for (const contextKey in childContext) {
+ if (!(contextKey in childContextTypes)) {
+ throw new Error((getComponentNameFromType(type) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes.");
+ }
+ }
+
+ return assign({}, parentContext, childContext);
+ }
+}
+
+// Forming a reverse tree.
+// The structure of a context snapshot is an implementation of this file.
+// Currently, it's implemented as tracking the current active node.
+
+
+const rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances.
+// This global (actually thread local) state represents what state all those "current",
+// fields are currently in.
+
+let currentActiveSnapshot = null;
+
+function popNode(prev) {
+ {
+ prev.context._currentValue = prev.parentValue;
+ }
+}
+
+function pushNode(next) {
+ {
+ next.context._currentValue = next.value;
+ }
+}
+
+function popToNearestCommonAncestor(prev, next) {
+ if (prev === next) ; else {
+ popNode(prev);
+ const parentPrev = prev.parent;
+ const parentNext = next.parent;
+
+ if (parentPrev === null) {
+ if (parentNext !== null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+ } else {
+ if (parentNext === null) {
+ throw new Error('The stacks must reach the root at the same time. This is a bug in React.');
+ }
+
+ popToNearestCommonAncestor(parentPrev, parentNext);
+ } // On the way back, we push the new ones that weren't common.
+
+
+ pushNode(next);
+ }
+}
+
+function popAllPrevious(prev) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev !== null) {
+ popAllPrevious(parentPrev);
+ }
+}
+
+function pushAllNext(next) {
+ const parentNext = next.parent;
+
+ if (parentNext !== null) {
+ pushAllNext(parentNext);
+ }
+
+ pushNode(next);
+}
+
+function popPreviousToCommonLevel(prev, next) {
+ popNode(prev);
+ const parentPrev = prev.parent;
+
+ if (parentPrev === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (parentPrev.depth === next.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(parentPrev, next);
+ } else {
+ // We must still be deeper.
+ popPreviousToCommonLevel(parentPrev, next);
+ }
+}
+
+function popNextToCommonLevel(prev, next) {
+ const parentNext = next.parent;
+
+ if (parentNext === null) {
+ throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.');
+ }
+
+ if (prev.depth === parentNext.depth) {
+ // We found the same level. Now we just need to find a shared ancestor.
+ popToNearestCommonAncestor(prev, parentNext);
+ } else {
+ // We must still be deeper.
+ popNextToCommonLevel(prev, parentNext);
+ }
+
+ pushNode(next);
+} // Perform context switching to the new snapshot.
+// To make it cheap to read many contexts, while not suspending, we make the switch eagerly by
+// updating all the context's current values. That way reads, always just read the current value.
+// At the cost of updating contexts even if they're never read by this subtree.
+
+
+function switchContext(newSnapshot) {
+ // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack.
+ // We also need to update any new contexts that are now on the stack with the deepest value.
+ // The easiest way to update new contexts is to just reapply them in reverse order from the
+ // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack
+ // for that. Therefore this algorithm is recursive.
+ // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go.
+ // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go.
+ // 3) Then we reapply new contexts on the way back up the stack.
+ const prev = currentActiveSnapshot;
+ const next = newSnapshot;
+
+ if (prev !== next) {
+ if (prev === null) {
+ // $FlowFixMe[incompatible-call]: This has to be non-null since it's not equal to prev.
+ pushAllNext(next);
+ } else if (next === null) {
+ popAllPrevious(prev);
+ } else if (prev.depth === next.depth) {
+ popToNearestCommonAncestor(prev, next);
+ } else if (prev.depth > next.depth) {
+ popPreviousToCommonLevel(prev, next);
+ } else {
+ popNextToCommonLevel(prev, next);
+ }
+
+ currentActiveSnapshot = next;
+ }
+}
+function pushProvider(context, nextValue) {
+ let prevValue;
+
+ {
+ prevValue = context._currentValue;
+ context._currentValue = nextValue;
+ }
+
+ const prevNode = currentActiveSnapshot;
+ const newNode = {
+ parent: prevNode,
+ depth: prevNode === null ? 0 : prevNode.depth + 1,
+ context: context,
+ parentValue: prevValue,
+ value: nextValue
+ };
+ currentActiveSnapshot = newNode;
+ return newNode;
+}
+function popProvider(context) {
+ const prevSnapshot = currentActiveSnapshot;
+
+ if (prevSnapshot === null) {
+ throw new Error('Tried to pop a Context at the root of the app. This is a bug in React.');
+ }
+
+ {
+ const value = prevSnapshot.parentValue;
+
+ if (value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) {
+ prevSnapshot.context._currentValue = prevSnapshot.context._defaultValue;
+ } else {
+ prevSnapshot.context._currentValue = value;
+ }
+ }
+
+ return currentActiveSnapshot = prevSnapshot.parent;
+}
+function getActiveContext() {
+ return currentActiveSnapshot;
+}
+function readContext$1(context) {
+ const value = context._currentValue ;
+ return value;
+}
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ *
+ * Note that this module is currently shared and assumed to be stateless.
+ * If this becomes an actual Map, that will break.
+ */
+function get(key) {
+ return key._reactInternals;
+}
+function set(key, value) {
+ key._reactInternals = value;
+}
+
+const classComponentUpdater = {
+ isMounted(inst) {
+ return false;
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueSetState(inst, payload, callback) {
+ const internals = get(inst);
+
+ if (internals.queue === null) ; else {
+ internals.queue.push(payload);
+ }
+ },
+
+ enqueueReplaceState(inst, payload, callback) {
+ const internals = get(inst);
+ internals.replace = true;
+ internals.queue = [payload];
+ },
+
+ // $FlowFixMe[missing-local-annot]
+ enqueueForceUpdate(inst, callback) {
+ }
+
+};
+
+function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) {
+ const partialState = getDerivedStateFromProps(nextProps, prevState);
+
+
+ const newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);
+ return newState;
+}
+
+function constructClassInstance(ctor, props, maskedLegacyContext) {
+ let context = emptyContextObject;
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ context = readContext$1(contextType);
+ } else {
+ context = maskedLegacyContext;
+ }
+
+ const instance = new ctor(props, context);
+
+ return instance;
+}
+
+function callComponentWillMount(type, instance) {
+ const oldState = instance.state;
+
+ if (typeof instance.componentWillMount === 'function') {
+
+ instance.componentWillMount();
+ }
+
+ if (typeof instance.UNSAFE_componentWillMount === 'function') {
+ instance.UNSAFE_componentWillMount();
+ }
+
+ if (oldState !== instance.state) {
+
+ classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
+ }
+}
+
+function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) {
+ if (internalInstance.queue !== null && internalInstance.queue.length > 0) {
+ const oldQueue = internalInstance.queue;
+ const oldReplace = internalInstance.replace;
+ internalInstance.queue = null;
+ internalInstance.replace = false;
+
+ if (oldReplace && oldQueue.length === 1) {
+ inst.state = oldQueue[0];
+ } else {
+ let nextState = oldReplace ? oldQueue[0] : inst.state;
+ let dontMutate = true;
+
+ for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {
+ const partial = oldQueue[i];
+ const partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial;
+
+ if (partialState != null) {
+ if (dontMutate) {
+ dontMutate = false;
+ nextState = assign({}, nextState, partialState);
+ } else {
+ assign(nextState, partialState);
+ }
+ }
+ }
+
+ inst.state = nextState;
+ }
+ } else {
+ internalInstance.queue = null;
+ }
+} // Invokes the mount life-cycles on a previously never rendered instance.
+
+
+function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) {
+
+ const initialState = instance.state !== undefined ? instance.state : null;
+ instance.updater = classComponentUpdater;
+ instance.props = newProps;
+ instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway.
+ // The internal instance will be used to manage updates that happen during this mount.
+
+ const internalInstance = {
+ queue: [],
+ replace: false
+ };
+ set(instance, internalInstance);
+ const contextType = ctor.contextType;
+
+ if (typeof contextType === 'object' && contextType !== null) {
+ instance.context = readContext$1(contextType);
+ } else {
+ instance.context = maskedLegacyContext;
+ }
+
+ const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
+
+ if (typeof getDerivedStateFromProps === 'function') {
+ instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps);
+ } // In order to support react-lifecycles-compat polyfilled components,
+ // Unsafe lifecycles should not be invoked for components using the new APIs.
+
+
+ if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
+ callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's
+ // process them now.
+
+ processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext);
+ }
+}
+
+// Ids are base 32 strings whose binary representation corresponds to the
+// position of a node in a tree.
+// Every time the tree forks into multiple children, we add additional bits to
+// the left of the sequence that represent the position of the child within the
+// current level of children.
+//
+// 00101 00010001011010101
+// ╰─┬─╯ ╰───────┬───────╯
+// Fork 5 of 20 Parent id
+//
+// The leading 0s are important. In the above example, you only need 3 bits to
+// represent slot 5. However, you need 5 bits to represent all the forks at
+// the current level, so we must account for the empty bits at the end.
+//
+// For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise,
+// the zeroth id at a level would be indistinguishable from its parent.
+//
+// If a node has only one child, and does not materialize an id (i.e. does not
+// contain a useId hook), then we don't need to allocate any space in the
+// sequence. It's treated as a transparent indirection. For example, these two
+// trees produce the same ids:
+//
+// <> <>
+//
+//
+// >
+//
+// >
+//
+// However, we cannot skip any node that materializes an id. Otherwise, a parent
+// id that does not fork would be indistinguishable from its child id. For
+// example, this tree does not fork, but the parent and child must have
+// different ids.
+//
+//
+//
+//
+//
+// To handle this scenario, every time we materialize an id, we allocate a
+// new level with a single slot. You can think of this as a fork with only one
+// prong, or an array of children with length 1.
+//
+// It's possible for the size of the sequence to exceed 32 bits, the max
+// size for bitwise operations. When this happens, we make more room by
+// converting the right part of the id to a string and storing it in an overflow
+// variable. We use a base 32 string representation, because 32 is the largest
+// power of 2 that is supported by toString(). We want the base to be large so
+// that the resulting ids are compact, and we want the base to be a power of 2
+// because every log2(base) bits corresponds to a single character, i.e. every
+// log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without
+// affecting the final result.
+const emptyTreeContext = {
+ id: 1,
+ overflow: ''
+};
+function getTreeId(context) {
+ const overflow = context.overflow;
+ const idWithLeadingBit = context.id;
+ const id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);
+ return id.toString(32) + overflow;
+}
+function pushTreeContext(baseContext, totalChildren, index) {
+ const baseIdWithLeadingBit = baseContext.id;
+ const baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part
+ // of the id; we use it to account for leading 0s.
+
+ const baseLength = getBitLength(baseIdWithLeadingBit) - 1;
+ const baseId = baseIdWithLeadingBit & ~(1 << baseLength);
+ const slot = index + 1;
+ const length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into
+ // consideration the leading 1 we use to mark the end of the sequence.
+
+ if (length > 30) {
+ // We overflowed the bitwise-safe range. Fall back to slower algorithm.
+ // This branch assumes the length of the base id is greater than 5; it won't
+ // work for smaller ids, because you need 5 bits per character.
+ //
+ // We encode the id in multiple steps: first the base id, then the
+ // remaining digits.
+ //
+ // Each 5 bit sequence corresponds to a single base 32 character. So for
+ // example, if the current id is 23 bits long, we can convert 20 of those
+ // bits into a string of 4 characters, with 3 bits left over.
+ //
+ // First calculate how many bits in the base id represent a complete
+ // sequence of characters.
+ const numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.
+
+ const newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.
+
+ const newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.
+
+ const restOfBaseId = baseId >> numberOfOverflowBits;
+ const restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because
+ // we made more room, this time it won't overflow.
+
+ const restOfLength = getBitLength(totalChildren) + restOfBaseLength;
+ const restOfNewBits = slot << restOfBaseLength;
+ const id = restOfNewBits | restOfBaseId;
+ const overflow = newOverflow + baseOverflow;
+ return {
+ id: 1 << restOfLength | id,
+ overflow
+ };
+ } else {
+ // Normal path
+ const newBits = slot << baseLength;
+ const id = newBits | baseId;
+ const overflow = baseOverflow;
+ return {
+ id: 1 << length | id,
+ overflow
+ };
+ }
+}
+
+function getBitLength(number) {
+ return 32 - clz32(number);
+}
+
+function getLeadingBit(id) {
+ return 1 << getBitLength(id) - 1;
+} // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback.
+
+
+const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.
+// Based on:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+const log = Math.log;
+const LN2 = Math.LN2;
+
+function clz32Fallback(x) {
+ const asUint = x >>> 0;
+
+ if (asUint === 0) {
+ return 32;
+ }
+
+ return 31 - (log(asUint) / LN2 | 0) | 0;
+}
+
+// Corresponds to ReactFiberWakeable and ReactFlightWakeable modules. Generally,
+// changes to one module should be reflected in the others.
+// TODO: Rename this module and the corresponding Fiber one to "Thenable"
+// instead of "Wakeable". Or some other more appropriate name.
+// An error that is thrown (e.g. by `use`) to trigger Suspense. If we
+// detect this is caught by userspace, we'll log a warning in development.
+const SuspenseException = new Error("Suspense Exception: This is not a real error! It's an implementation " + 'detail of `use` to interrupt the current render. You must either ' + 'rethrow it immediately, or move the `use` call outside of the ' + '`try/catch` block. Capturing without rethrowing will lead to ' + 'unexpected behavior.\n\n' + 'To handle async errors, wrap your component in an error boundary, or ' + "call the promise's `.catch` method and pass the result to `use`");
+function createThenableState() {
+ // The ThenableState is created the first time a component suspends. If it
+ // suspends again, we'll reuse the same state.
+ return [];
+}
+
+function noop$2() {}
+
+function trackUsedThenable(thenableState, thenable, index) {
+ const previous = thenableState[index];
+
+ if (previous === undefined) {
+ thenableState.push(thenable);
+ } else {
+ if (previous !== thenable) {
+ // Reuse the previous thenable, and drop the new one. We can assume
+ // they represent the same value, because components are idempotent.
+ // Avoid an unhandled rejection errors for the Promises that we'll
+ // intentionally ignore.
+ thenable.then(noop$2, noop$2);
+ thenable = previous;
+ }
+ } // We use an expando to track the status and result of a thenable so that we
+ // can synchronously unwrap the value. Think of this as an extension of the
+ // Promise API, or a custom interface that is a superset of Thenable.
+ //
+ // If the thenable doesn't have a status, set it to "pending" and attach
+ // a listener that will update its status and result when it resolves.
+
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledValue = thenable.value;
+ return fulfilledValue;
+ }
+
+ case 'rejected':
+ {
+ const rejectedError = thenable.reason;
+ throw rejectedError;
+ }
+
+ default:
+ {
+ if (typeof thenable.status === 'string') ; else {
+ const pendingThenable = thenable;
+ pendingThenable.status = 'pending';
+ pendingThenable.then(fulfilledValue => {
+ if (thenable.status === 'pending') {
+ const fulfilledThenable = thenable;
+ fulfilledThenable.status = 'fulfilled';
+ fulfilledThenable.value = fulfilledValue;
+ }
+ }, error => {
+ if (thenable.status === 'pending') {
+ const rejectedThenable = thenable;
+ rejectedThenable.status = 'rejected';
+ rejectedThenable.reason = error;
+ }
+ }); // Check one more time in case the thenable resolved synchronously
+
+ switch (thenable.status) {
+ case 'fulfilled':
+ {
+ const fulfilledThenable = thenable;
+ return fulfilledThenable.value;
+ }
+
+ case 'rejected':
+ {
+ const rejectedThenable = thenable;
+ throw rejectedThenable.reason;
+ }
+ }
+ } // Suspend.
+ //
+ // Throwing here is an implementation detail that allows us to unwind the
+ // call stack. But we shouldn't allow it to leak into userspace. Throw an
+ // opaque placeholder value instead of the actual thenable. If it doesn't
+ // get captured by the work loop, log a warning, because that means
+ // something in userspace must have caught it.
+
+
+ suspendedThenable = thenable;
+ throw SuspenseException;
+ }
+ }
+} // This is used to track the actual thenable that suspended so it can be
+// passed to the rest of the Suspense implementation — which, for historical
+// reasons, expects to receive a thenable.
+
+let suspendedThenable = null;
+function getSuspendedThenable() {
+ // This is called right after `use` suspends by throwing an exception. `use`
+ // throws an opaque value instead of the thenable itself so that it can't be
+ // caught in userspace. Then the work loop accesses the actual thenable using
+ // this function.
+ if (suspendedThenable === null) {
+ throw new Error('Expected a suspended thenable. This is a bug in React. Please file ' + 'an issue.');
+ }
+
+ const thenable = suspendedThenable;
+ suspendedThenable = null;
+ return thenable;
+}
+
+/**
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+ */
+function is(x, y) {
+ return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
+ ;
+}
+
+const objectIs = // $FlowFixMe[method-unbinding]
+typeof Object.is === 'function' ? Object.is : is;
+
+let currentlyRenderingComponent = null;
+let currentlyRenderingTask = null;
+let currentlyRenderingRequest = null;
+let currentlyRenderingKeyPath = null;
+let firstWorkInProgressHook = null;
+let workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook
+
+let isReRender = false; // Whether an update was scheduled during the currently executing render pass.
+
+let didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component
+
+let localIdCounter = 0; // Chunks that should be pushed to the stream once the component
+// finishes rendering.
+// Counts the number of useFormState calls in this component
+
+let formStateCounter = 0; // The index of the useFormState hook that matches the one passed in at the
+// root during an MPA navigation, if any.
+
+let formStateMatchingIndex = -1; // Counts the number of use(thenable) calls in this component
+
+let thenableIndexCounter = 0;
+let thenableState = null; // Lazily created map of render-phase updates
+
+let renderPhaseUpdates = null; // Counter to prevent infinite loops.
+
+let numberOfReRenders = 0;
+const RE_RENDER_LIMIT = 25;
+
+function resolveCurrentlyRenderingComponent() {
+ if (currentlyRenderingComponent === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + '2. You might be breaking the Rules of Hooks\n' + '3. You might have more than one copy of React in the same app\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.');
+ }
+
+ return currentlyRenderingComponent;
+}
+
+function areHookInputsEqual(nextDeps, prevDeps) {
+ if (prevDeps === null) {
+
+ return false;
+ }
+
+
+ for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ if (objectIs(nextDeps[i], prevDeps[i])) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+function createHook() {
+ if (numberOfReRenders > 0) {
+ throw new Error('Rendered more hooks than during the previous render');
+ }
+
+ return {
+ memoizedState: null,
+ queue: null,
+ next: null
+ };
+}
+
+function createWorkInProgressHook() {
+ if (workInProgressHook === null) {
+ // This is the first hook in the list
+ if (firstWorkInProgressHook === null) {
+ isReRender = false;
+ firstWorkInProgressHook = workInProgressHook = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = firstWorkInProgressHook;
+ }
+ } else {
+ if (workInProgressHook.next === null) {
+ isReRender = false; // Append to the end of the list
+
+ workInProgressHook = workInProgressHook.next = createHook();
+ } else {
+ // There's already a work-in-progress. Reuse it.
+ isReRender = true;
+ workInProgressHook = workInProgressHook.next;
+ }
+ }
+
+ return workInProgressHook;
+}
+
+function prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState) {
+ currentlyRenderingComponent = componentIdentity;
+ currentlyRenderingTask = task;
+ currentlyRenderingRequest = request;
+ currentlyRenderingKeyPath = keyPath;
+ // didScheduleRenderPhaseUpdate = false;
+ // firstWorkInProgressHook = null;
+ // numberOfReRenders = 0;
+ // renderPhaseUpdates = null;
+ // workInProgressHook = null;
+
+
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ thenableState = prevThenableState;
+}
+function finishHooks(Component, props, children, refOrContext) {
+ // This must be called after every function component to prevent hooks from
+ // being used in classes.
+ while (didScheduleRenderPhaseUpdate) {
+ // Updates were scheduled during the render phase. They are stored in
+ // the `renderPhaseUpdates` map. Call the component again, reusing the
+ // work-in-progress hooks and applying the additional updates on top. Keep
+ // restarting until no more updates are scheduled.
+ didScheduleRenderPhaseUpdate = false;
+ localIdCounter = 0;
+ formStateCounter = 0;
+ formStateMatchingIndex = -1;
+ thenableIndexCounter = 0;
+ numberOfReRenders += 1; // Start over from the beginning of the list
+
+ workInProgressHook = null;
+ children = Component(props, refOrContext);
+ }
+
+ resetHooksState();
+ return children;
+}
+function getThenableStateAfterSuspending() {
+ const state = thenableState;
+ thenableState = null;
+ return state;
+}
+function checkDidRenderIdHook() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ const didRenderIdHook = localIdCounter !== 0;
+ return didRenderIdHook;
+}
+function getFormStateCount() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateCounter;
+}
+function getFormStateMatchingIndex() {
+ // This should be called immediately after every finishHooks call.
+ // Conceptually, it's part of the return value of finishHooks; it's only a
+ // separate function to avoid using an array tuple.
+ return formStateMatchingIndex;
+} // Reset the internal hooks state if an error occurs while rendering a component
+
+function resetHooksState() {
+
+ currentlyRenderingComponent = null;
+ currentlyRenderingTask = null;
+ currentlyRenderingRequest = null;
+ currentlyRenderingKeyPath = null;
+ didScheduleRenderPhaseUpdate = false;
+ firstWorkInProgressHook = null;
+ numberOfReRenders = 0;
+ renderPhaseUpdates = null;
+ workInProgressHook = null;
+}
+
+function readContext(context) {
+
+ return readContext$1(context);
+}
+
+function useContext(context) {
+
+ resolveCurrentlyRenderingComponent();
+ return readContext$1(context);
+}
+
+function basicStateReducer(state, action) {
+ // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types
+ return typeof action === 'function' ? action(state) : action;
+}
+
+function useState(initialState) {
+
+ return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers
+ initialState);
+}
+function useReducer(reducer, initialArg, init) {
+
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+
+ if (isReRender) {
+ // This is a re-render. Apply the new render phase updates to the previous
+ // current hook.
+ const queue = workInProgressHook.queue;
+ const dispatch = queue.dispatch;
+
+ if (renderPhaseUpdates !== null) {
+ // Render phase updates are stored in a map of queue -> linked list
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate !== undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.delete(queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ let newState = workInProgressHook.memoizedState;
+ let update = firstRenderPhaseUpdate;
+
+ do {
+ // Process this render phase update. We don't have to check the
+ // priority because it will always be the same as the current
+ // render's.
+ const action = update.action;
+
+ newState = reducer(newState, action);
+
+
+ update = update.next;
+ } while (update !== null); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ workInProgressHook.memoizedState = newState;
+ return [newState, dispatch];
+ }
+ } // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+
+ return [workInProgressHook.memoizedState, dispatch];
+ } else {
+
+ let initialState;
+
+ if (reducer === basicStateReducer) {
+ // Special case for `useState`.
+ initialState = typeof initialArg === 'function' ? initialArg() : initialArg;
+ } else {
+ initialState = init !== undefined ? init(initialArg) : initialArg;
+ }
+
+
+ workInProgressHook.memoizedState = initialState; // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ const queue = workInProgressHook.queue = {
+ last: null,
+ dispatch: null
+ };
+ const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, queue); // $FlowFixMe[incompatible-use] found when upgrading Flow
+
+ return [workInProgressHook.memoizedState, dispatch];
+ }
+}
+
+function useMemo(nextCreate, deps) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const nextDeps = deps === undefined ? null : deps;
+
+ if (workInProgressHook !== null) {
+ const prevState = workInProgressHook.memoizedState;
+
+ if (prevState !== null) {
+ if (nextDeps !== null) {
+ const prevDeps = prevState[1];
+
+ if (areHookInputsEqual(nextDeps, prevDeps)) {
+ return prevState[0];
+ }
+ }
+ }
+ }
+
+ const nextValue = nextCreate();
+
+
+ workInProgressHook.memoizedState = [nextValue, nextDeps];
+ return nextValue;
+}
+
+function useRef(initialValue) {
+ currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
+ workInProgressHook = createWorkInProgressHook();
+ const previousRef = workInProgressHook.memoizedState;
+
+ if (previousRef === null) {
+ const ref = {
+ current: initialValue
+ };
+
+
+ workInProgressHook.memoizedState = ref;
+ return ref;
+ } else {
+ return previousRef;
+ }
+}
+
+function dispatchAction(componentIdentity, queue, action) {
+ if (numberOfReRenders >= RE_RENDER_LIMIT) {
+ throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.');
+ }
+
+ if (componentIdentity === currentlyRenderingComponent) {
+ // This is a render phase update. Stash it in a lazily-created map of
+ // queue -> linked list of updates. After this render pass, we'll restart
+ // and apply the stashed updates on top of the work-in-progress hook.
+ didScheduleRenderPhaseUpdate = true;
+ const update = {
+ action,
+ next: null
+ };
+
+ if (renderPhaseUpdates === null) {
+ renderPhaseUpdates = new Map();
+ }
+
+ const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
+
+ if (firstRenderPhaseUpdate === undefined) {
+ // $FlowFixMe[incompatible-use] found when upgrading Flow
+ renderPhaseUpdates.set(queue, update);
+ } else {
+ // Append the update to the end of the list.
+ let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
+
+ while (lastRenderPhaseUpdate.next !== null) {
+ lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
+ }
+
+ lastRenderPhaseUpdate.next = update;
+ }
+ }
+}
+
+function useCallback(callback, deps) {
+ return useMemo(() => callback, deps);
+}
+
+function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
+ if (getServerSnapshot === undefined) {
+ throw new Error('Missing getServerSnapshot, which is required for ' + 'server-rendered content. Will revert to client rendering.');
+ }
+
+ return getServerSnapshot();
+}
+
+function useDeferredValue(value, initialValue) {
+ resolveCurrentlyRenderingComponent();
+
+ {
+ return value;
+ }
+}
+
+function unsupportedStartTransition() {
+ throw new Error('startTransition cannot be called during server rendering.');
+}
+
+function useTransition() {
+ resolveCurrentlyRenderingComponent();
+ return [false, unsupportedStartTransition];
+}
+
+function useHostTransitionStatus() {
+ resolveCurrentlyRenderingComponent();
+ return NotPendingTransition;
+}
+
+function unsupportedSetOptimisticState() {
+ throw new Error('Cannot update optimistic state while rendering.');
+}
+
+function useOptimistic(passthrough, reducer) {
+ resolveCurrentlyRenderingComponent();
+ return [passthrough, unsupportedSetOptimisticState];
+}
+
+function createPostbackFormStateKey(permalink, componentKeyPath, hookIndex) {
+ if (permalink !== undefined) {
+ // Don't bother to hash a permalink-based key since it's already short.
+ return 'p' + permalink;
+ } else {
+ // Append a node to the key path that represents the form state hook.
+ const keyPath = [componentKeyPath, null, hookIndex]; // Key paths are hashed to reduce the size. It does not need to be secure,
+ // and it's more important that it's fast than that it's completely
+ // collision-free.
+
+ const keyPathHash = createFastHash(JSON.stringify(keyPath));
+ return 'k' + keyPathHash;
+ }
+}
+
+function useFormState(action, initialState, permalink) {
+ resolveCurrentlyRenderingComponent(); // Count the number of useFormState hooks per component. We also use this to
+ // track the position of this useFormState hook relative to the other ones in
+ // this component, so we can generate a unique key for each one.
+
+ const formStateHookIndex = formStateCounter++;
+ const request = currentlyRenderingRequest; // $FlowIgnore[prop-missing]
+
+ const formAction = action.$$FORM_ACTION;
+
+ if (typeof formAction === 'function') {
+ // This is a server action. These have additional features to enable
+ // MPA-style form submissions with progressive enhancement.
+ // TODO: If the same permalink is passed to multiple useFormStates, and
+ // they all have the same action signature, Fizz will pass the postback
+ // state to all of them. We should probably only pass it to the first one,
+ // and/or warn.
+ // The key is lazily generated and deduped so the that the keypath doesn't
+ // get JSON.stringify-ed unnecessarily, and at most once.
+ let nextPostbackStateKey = null; // Determine the current form state. If we received state during an MPA form
+ // submission, then we will reuse that, if the action identity matches.
+ // Otherwise we'll use the initial state argument. We will emit a comment
+ // marker into the stream that indicates whether the state was reused.
+
+ let state = initialState;
+ const componentKeyPath = currentlyRenderingKeyPath;
+ const postbackFormState = getFormState(request); // $FlowIgnore[prop-missing]
+
+ const isSignatureEqual = action.$$IS_SIGNATURE_EQUAL;
+
+ if (postbackFormState !== null && typeof isSignatureEqual === 'function') {
+ const postbackKey = postbackFormState[1];
+ const postbackReferenceId = postbackFormState[2];
+ const postbackBoundArity = postbackFormState[3];
+
+ if (isSignatureEqual.call(action, postbackReferenceId, postbackBoundArity)) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+
+ if (postbackKey === nextPostbackStateKey) {
+ // This was a match
+ formStateMatchingIndex = formStateHookIndex; // Reuse the state that was submitted by the form.
+
+ state = postbackFormState[0];
+ }
+ }
+ } // Bind the state to the first argument of the action.
+
+
+ const boundAction = action.bind(null, state); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ }; // $FlowIgnore[prop-missing]
+
+
+ if (typeof boundAction.$$FORM_ACTION === 'function') {
+ // $FlowIgnore[prop-missing]
+ dispatch.$$FORM_ACTION = prefix => {
+ const metadata = boundAction.$$FORM_ACTION(prefix); // Override the action URL
+
+ if (permalink !== undefined) {
+
+ permalink += '';
+ metadata.action = permalink;
+ }
+
+ const formData = metadata.data;
+
+ if (formData) {
+ if (nextPostbackStateKey === null) {
+ nextPostbackStateKey = createPostbackFormStateKey(permalink, componentKeyPath, formStateHookIndex);
+ }
+
+ formData.append('$ACTION_KEY', nextPostbackStateKey);
+ }
+
+ return metadata;
+ };
+ }
+
+ return [state, dispatch];
+ } else {
+ // This is not a server action, so the implementation is much simpler.
+ // Bind the state to the first argument of the action.
+ const boundAction = action.bind(null, initialState); // Wrap the action so the return value is void.
+
+ const dispatch = payload => {
+ boundAction(payload);
+ };
+
+ return [initialState, dispatch];
+ }
+}
+
+function useId() {
+ const task = currentlyRenderingTask;
+ const treeId = getTreeId(task.treeContext);
+ const resumableState = currentResumableState;
+
+ if (resumableState === null) {
+ throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component.');
+ }
+
+ const localId = localIdCounter++;
+ return makeId(resumableState, treeId, localId);
+}
+
+function use(usable) {
+ if (usable !== null && typeof usable === 'object') {
+ // $FlowFixMe[method-unbinding]
+ if (typeof usable.then === 'function') {
+ // This is a thenable.
+ const thenable = usable;
+ return unwrapThenable(thenable);
+ } else if (usable.$$typeof === REACT_CONTEXT_TYPE || usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = usable;
+ return readContext(context);
+ }
+ } // eslint-disable-next-line react-internal/safe-string-coercion
+
+
+ throw new Error('An unsupported type was passed to use(): ' + String(usable));
+}
+
+function unwrapThenable(thenable) {
+ const index = thenableIndexCounter;
+ thenableIndexCounter += 1;
+
+ if (thenableState === null) {
+ thenableState = createThenableState();
+ }
+
+ return trackUsedThenable(thenableState, thenable, index);
+}
+
+function unsupportedRefresh() {
+ throw new Error('Cache cannot be refreshed during server rendering.');
+}
+
+function useCacheRefresh() {
+ return unsupportedRefresh;
+}
+
+function noop$1() {}
+
+const HooksDispatcher = {
+ readContext,
+ use,
+ useContext,
+ useMemo,
+ useReducer,
+ useRef,
+ useState,
+ useInsertionEffect: noop$1,
+ useLayoutEffect: noop$1,
+ useCallback,
+ // useImperativeHandle is not run in the server environment
+ useImperativeHandle: noop$1,
+ // Effects are not run in the server environment.
+ useEffect: noop$1,
+ // Debugging effect
+ useDebugValue: noop$1,
+ useDeferredValue,
+ useTransition,
+ useId,
+ // Subscriptions are not setup in a server environment.
+ useSyncExternalStore
+};
+
+{
+ HooksDispatcher.useCacheRefresh = useCacheRefresh;
+}
+
+{
+ HooksDispatcher.useHostTransitionStatus = useHostTransitionStatus;
+}
+
+{
+ HooksDispatcher.useOptimistic = useOptimistic;
+ HooksDispatcher.useFormState = useFormState;
+}
+
+let currentResumableState = null;
+function setCurrentResumableState(resumableState) {
+ currentResumableState = resumableState;
+}
+
+function getCacheSignal() {
+ throw new Error('Not implemented.');
+}
+
+function getCacheForType(resourceType) {
+ throw new Error('Not implemented.');
+}
+
+const DefaultCacheDispatcher = {
+ getCacheSignal,
+ getCacheForType
+};
+
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
+const ReactCurrentCache = ReactSharedInternals.ReactCurrentCache;
+// The name might be minified but we assume that it's going to be the same generated name. Typically
+// because it's just the same compiled output in practice.
+// resume with segmentID at the index
+
+const CLIENT_RENDERED = 4; // if it errors or infinitely suspends
+
+const PENDING = 0;
+const COMPLETED = 1;
+const FLUSHED = 2;
+const ABORTED = 3;
+const ERRORED = 4;
+const POSTPONED = 5;
+const OPEN = 0;
+const CLOSING = 1;
+const CLOSED = 2; // This is a default heuristic for how to split up the HTML content into progressive
+// loading. Our goal is to be able to display additional new content about every 500ms.
+// Faster than that is unnecessary and should be throttled on the client. It also
+// adds unnecessary overhead to do more splits. We don't know if it's a higher or lower
+// end device but higher end suffer less from the overhead than lower end does from
+// not getting small enough pieces. We error on the side of low end.
+// We base this on low end 3G speeds which is about 500kbits per second. We assume
+// that there can be a reasonable drop off from max bandwidth which leaves you with
+// as little as 80%. We can receive half of that each 500ms - at best. In practice,
+// a little bandwidth is lost to processing and contention - e.g. CSS and images that
+// are downloaded along with the main content. So we estimate about half of that to be
+// the lower end throughput. In other words, we expect that you can at least show
+// about 12.5kb of content per 500ms. Not counting starting latency for the first
+// paint.
+// 500 * 1024 / 8 * .8 * 0.5 / 2
+
+const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
+
+function defaultErrorHandler(error) {
+ console['error'](error); // Don't transform to our wrapper
+
+ return null;
+}
+
+function noop() {}
+
+function createRequest(children, resumableState, renderState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError, onPostpone, formState) {
+ prepareHostDispatcher();
+ const pingedTasks = [];
+ const abortSet = new Set();
+ const request = {
+ destination: null,
+ flushScheduled: false,
+ resumableState,
+ renderState,
+ rootFormatContext,
+ progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize,
+ status: OPEN,
+ fatalError: null,
+ nextSegmentId: 0,
+ allPendingTasks: 0,
+ pendingRootTasks: 0,
+ completedRootSegment: null,
+ abortableTasks: abortSet,
+ pingedTasks: pingedTasks,
+ clientRenderedBoundaries: [],
+ completedBoundaries: [],
+ partialBoundaries: [],
+ trackedPostpones: null,
+ onError: onError === undefined ? defaultErrorHandler : onError,
+ onPostpone: onPostpone === undefined ? noop : onPostpone,
+ onAllReady: onAllReady === undefined ? noop : onAllReady,
+ onShellReady: onShellReady === undefined ? noop : onShellReady,
+ onShellError: onShellError === undefined ? noop : onShellError,
+ onFatalError: onFatalError === undefined ? noop : onFatalError,
+ formState: formState === undefined ? null : formState
+ }; // This segment represents the root fallback.
+
+ const rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge
+ false, false); // There is no parent so conceptually, we're unblocked to flush this segment.
+
+ rootSegment.parentFlushed = true;
+ const rootTask = createRenderTask(request, null, children, -1, null, rootSegment, abortSet, null, rootFormatContext, emptyContextObject, rootContextSnapshot, emptyTreeContext);
+ pingedTasks.push(rootTask);
+ return request;
+}
+let currentRequest = null;
+function resolveRequest() {
+ if (currentRequest) return currentRequest;
+
+ {
+ const store = requestStorage.getStore();
+ if (store) return store;
+ }
+
+ return null;
+}
+
+function pingTask(request, task) {
+ const pingedTasks = request.pingedTasks;
+ pingedTasks.push(task);
+
+ if (request.pingedTasks.length === 1) {
+ request.flushScheduled = request.destination !== null;
+ scheduleWork(() => performWork(request));
+ }
+}
+
+function createSuspenseBoundary(request, fallbackAbortableTasks) {
+ return {
+ status: PENDING,
+ rootSegmentID: -1,
+ parentFlushed: false,
+ pendingTasks: 0,
+ completedSegments: [],
+ byteSize: 0,
+ fallbackAbortableTasks,
+ errorDigest: null,
+ resources: createBoundaryResources(),
+ trackedContentKeyPath: null,
+ trackedFallbackNode: null
+ };
+}
+
+function createRenderTask(request, thenableState, node, childIndex, blockedBoundary, blockedSegment, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ const task = {
+ replay: null,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createReplayTask(request, thenableState, replay, node, childIndex, blockedBoundary, abortSet, keyPath, formatContext, legacyContext, context, treeContext) {
+ request.allPendingTasks++;
+
+ if (blockedBoundary === null) {
+ request.pendingRootTasks++;
+ } else {
+ blockedBoundary.pendingTasks++;
+ }
+
+ replay.pendingTasks++;
+ const task = {
+ replay,
+ node,
+ childIndex,
+ ping: () => pingTask(request, task),
+ blockedBoundary,
+ blockedSegment: null,
+ abortSet,
+ keyPath,
+ formatContext,
+ legacyContext,
+ context,
+ treeContext,
+ thenableState
+ };
+
+ abortSet.add(task);
+ return task;
+}
+
+function createPendingSegment(request, index, boundary, parentFormatContext, lastPushedText, textEmbedded) {
+ return {
+ status: PENDING,
+ id: -1,
+ // lazily assigned later
+ index,
+ parentFlushed: false,
+ chunks: [],
+ children: [],
+ parentFormatContext,
+ boundary,
+ lastPushedText,
+ textEmbedded
+ };
+} // DEV-only global reference to the currently executing task
+
+function popComponentStackInDEV(task) {
+} // stash the component stack of an unwinding error until it is processed
+
+function logRecoverableError(request, error) {
+ // If this callback errors, we intentionally let that error bubble up to become a fatal error
+ // so that someone fixes the error reporting instead of hiding it.
+ const errorDigest = request.onError(error);
+
+ if (errorDigest != null && typeof errorDigest !== 'string') {
+ // eslint-disable-next-line react-internal/prod-error-codes
+ throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead");
+ }
+
+ return errorDigest;
+}
+
+function fatalError(request, error) {
+ // This is called outside error handling code such as if the root errors outside
+ // a suspense boundary or if the root suspense boundary's fallback errors.
+ // It's also called if React itself or its host configs errors.
+ const onShellError = request.onShellError;
+ onShellError(error);
+ const onFatalError = request.onFatalError;
+ onFatalError(error);
+
+ if (request.destination !== null) {
+ request.status = CLOSED;
+ closeWithError(request.destination, error);
+ } else {
+ request.status = CLOSING;
+ request.fatalError = error;
+ }
+}
+
+function renderSuspenseBoundary(request, someTask, keyPath, props) {
+ if (someTask.replay !== null) {
+ // If we're replaying through this pass, it means we're replaying through
+ // an already completed Suspense boundary. It's too late to do anything about it
+ // so we can just render through it.
+ const prevKeyPath = someTask.keyPath;
+ someTask.keyPath = keyPath;
+ const content = props.children;
+
+ try {
+ renderNode(request, someTask, content, -1);
+ } finally {
+ someTask.keyPath = prevKeyPath;
+ }
+
+ return;
+ } // $FlowFixMe: Refined.
+
+
+ const task = someTask;
+ const prevKeyPath = task.keyPath;
+ const parentBoundary = task.blockedBoundary;
+ const parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for
+ // the fallback so that we can later replace that segment with the content.
+ // This also lets us split out the main content even if it doesn't suspend,
+ // in case it ends up generating a large subtree of content.
+
+ const fallback = props.fallback;
+ const content = props.children;
+ const fallbackAbortSet = new Set();
+ const newBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+
+ if (request.trackedPostpones !== null) {
+ newBoundary.trackedContentKeyPath = keyPath;
+ }
+
+ const insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback.
+
+ const boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false);
+ parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent
+
+ parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately.
+
+ const contentRootSegment = createPendingSegment(request, 0, null, task.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them
+ false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is
+ // no parent segment so there's nothing to wait on.
+
+ contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks.
+ // I suspect that there might be some efficiency benefits from not creating the suspended task
+ // and instead just using the stack if possible.
+ // TODO: Call this directly instead of messing with saving and restoring contexts.
+ // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and which segment
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = newBoundary;
+ task.blockedSegment = contentRootSegment;
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, newBoundary.resources);
+ }
+
+ task.keyPath = keyPath;
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+ pushSegmentFinale(contentRootSegment.chunks, request.renderState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded);
+ contentRootSegment.status = COMPLETED;
+ queueCompletedSegment(newBoundary, contentRootSegment);
+
+ if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
+ newBoundary.status = COMPLETED; // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ contentRootSegment.status = ERRORED;
+ newBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ newBoundary.errorDigest = errorDigest;
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.blockedSegment = parentSegment;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]];
+ const trackedPostpones = request.trackedPostpones;
+
+ if (trackedPostpones !== null) {
+ // We create a detached replay node to track any postpones inside the fallback.
+ const fallbackReplayNode = [fallbackKeyPath[1], fallbackKeyPath[2], [], null];
+ trackedPostpones.workingMap.set(fallbackKeyPath, fallbackReplayNode);
+
+ if (newBoundary.status === POSTPONED) {
+ // This must exist now.
+ const boundaryReplayNode = trackedPostpones.workingMap.get(keyPath);
+ boundaryReplayNode[4] = fallbackReplayNode;
+ } else {
+ // We might not inject it into the postponed tree, unless the content actually
+ // postpones too. We need to keep track of it until that happpens.
+ newBoundary.trackedFallbackNode = fallbackReplayNode;
+ }
+ } // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+
+ const suspendedFallbackTask = createRenderTask(request, null, fallback, -1, parentBoundary, boundarySegment, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function replaySuspenseBoundary(request, task, keyPath, props, id, childNodes, childSlots, fallbackNodes, fallbackSlots) {
+ const prevKeyPath = task.keyPath;
+ const previousReplaySet = task.replay;
+ const parentBoundary = task.blockedBoundary;
+ const content = props.children;
+ const fallback = props.fallback;
+ const fallbackAbortSet = new Set();
+ const resumedBoundary = createSuspenseBoundary(request, fallbackAbortSet);
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = id; // We can reuse the current context and task to render the content immediately without
+ // context switching. We just need to temporarily switch which boundary and replay node
+ // we're writing to. If something suspends, it'll spawn new suspended task with that context.
+
+ task.blockedBoundary = resumedBoundary;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, resumedBoundary.resources);
+ }
+
+ try {
+ // We use the safe form because we don't handle suspending here. Only error handling.
+ renderNode(request, task, content, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+
+ if (resumedBoundary.pendingTasks === 0 && resumedBoundary.status === PENDING) {
+ resumedBoundary.status = COMPLETED;
+ request.completedBoundaries.push(resumedBoundary); // This must have been the last segment we were waiting on. This boundary is now complete.
+ // Therefore we won't need the fallback. We early return so that we don't have to create
+ // the fallback.
+
+ popComponentStackInDEV(task);
+ return;
+ }
+ } catch (error) {
+ resumedBoundary.status = CLIENT_RENDERED;
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ resumedBoundary.errorDigest = errorDigest;
+
+ task.replay.pendingTasks--; // The parent already flushed in the prerender so we need to schedule this to be emitted.
+
+ request.clientRenderedBoundaries.push(resumedBoundary); // We don't need to decrement any task numbers because we didn't spawn any new task.
+ // We don't need to schedule any task because we know the parent has written yet.
+ // We do need to fallthrough to create the fallback though.
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, parentBoundary ? parentBoundary.resources : null);
+ }
+
+ task.blockedBoundary = parentBoundary;
+ task.replay = previousReplaySet;
+ task.keyPath = prevKeyPath;
+ }
+
+ const fallbackKeyPath = [keyPath[0], 'Suspense Fallback', keyPath[2]]; // We create suspended task for the fallback because we don't want to actually work
+ // on it yet in case we finish the main content, so we queue for later.
+
+ const fallbackReplay = {
+ nodes: fallbackNodes,
+ slots: fallbackSlots,
+ pendingTasks: 0
+ };
+ const suspendedFallbackTask = createReplayTask(request, null, fallbackReplay, fallback, -1, parentBoundary, fallbackAbortSet, fallbackKeyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+ // on preparing fallbacks if we don't have any more main content to task on.
+
+
+ request.pingedTasks.push(suspendedFallbackTask);
+}
+
+function renderHostElement(request, task, keyPath, type, props) {
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ const children = props.children; // TODO: Make this a Config for replaying.
+
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ } else {
+ // Render
+ const children = pushStartInstance(segment.chunks, type, props, request.resumableState, request.renderState, task.formatContext, segment.lastPushedText);
+ segment.lastPushedText = false;
+ const prevContext = task.formatContext;
+ const prevKeyPath = task.keyPath;
+ task.formatContext = getChildFormatContext(prevContext, type, props);
+ task.keyPath = keyPath; // We use the non-destructive form because if something suspends, we still
+ // need to pop back up and finish this subtree of HTML.
+
+ renderNode(request, task, children, -1); // We expect that errors will fatal the whole task and that we don't need
+ // the correct context. Therefore this is not in a finally.
+
+ task.formatContext = prevContext;
+ task.keyPath = prevKeyPath;
+ pushEndInstance(segment.chunks, type, props, request.resumableState, prevContext);
+ segment.lastPushedText = false;
+ }
+}
+
+function shouldConstruct(Component) {
+ return Component.prototype && Component.prototype.isReactComponent;
+}
+
+function renderWithHooks(request, task, keyPath, prevThenableState, Component, props, secondArg) {
+ const componentIdentity = {};
+ prepareToUseHooks(request, task, keyPath, componentIdentity, prevThenableState);
+ const result = Component(props, secondArg);
+ return finishHooks(Component, props, result, secondArg);
+}
+
+function finishClassComponent(request, task, keyPath, instance, Component, props) {
+ const nextChildren = instance.render();
+
+ {
+ const childContextTypes = Component.childContextTypes;
+
+ if (childContextTypes !== null && childContextTypes !== undefined) {
+ const previousContext = task.legacyContext;
+ const mergedContext = processChildContext(instance, Component, previousContext, childContextTypes);
+ task.legacyContext = mergedContext;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.legacyContext = previousContext;
+ return;
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, nextChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderClassComponent(request, task, keyPath, Component, props) {
+ const maskedContext = getMaskedContext(Component, task.legacyContext) ;
+ const instance = constructClassInstance(Component, props, maskedContext);
+ mountClassInstance(instance, Component, props, maskedContext);
+ finishClassComponent(request, task, keyPath, instance, Component);
+}
+// components for some reason.
+
+function renderIndeterminateComponent(request, task, keyPath, prevThenableState, Component, props) {
+ let legacyContext;
+
+ {
+ legacyContext = getMaskedContext(Component, task.legacyContext);
+ }
+
+ const value = renderWithHooks(request, task, keyPath, prevThenableState, Component, props, legacyContext);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+
+ if ( // Run these checks in production only if the flag is off.
+ // Eventually we'll delete this branch altogether.
+ typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
+
+ mountClassInstance(value, Component, props, legacyContext);
+ finishClassComponent(request, task, keyPath, value, Component);
+ } else {
+
+ finishFunctionComponent(request, task, keyPath, value, hasId, formStateCount, formStateMatchingIndex);
+ }
+}
+
+function finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex) {
+ let didEmitFormStateMarkers = false;
+
+ if (formStateCount !== 0 && request.formState !== null) {
+ // For each useFormState hook, emit a marker that indicates whether we
+ // rendered using the form state passed at the root. We only emit these
+ // markers if form state is passed at the root.
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ didEmitFormStateMarkers = true;
+ const target = segment.chunks;
+
+ for (let i = 0; i < formStateCount; i++) {
+ if (i === formStateMatchingIndex) {
+ pushFormStateMarkerIsMatching(target);
+ } else {
+ pushFormStateMarkerIsNotMatching(target);
+ }
+ }
+ }
+ }
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+
+ if (hasId) {
+ // This component materialized an id. We treat this as its own level, with
+ // a single "child" slot.
+ const prevTreeContext = task.treeContext;
+ const totalChildren = 1;
+ const index = 0; // Modify the id context. Because we'll need to reset this if something
+ // suspends or errors, we'll use the non-destructive render path.
+
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index);
+ renderNode(request, task, children, -1); // Like the other contexts, this does not need to be in a finally block
+ // because renderNode takes care of unwinding the stack.
+
+ task.treeContext = prevTreeContext;
+ } else if (didEmitFormStateMarkers) {
+ // If there were formState hooks, we must use the non-destructive path
+ // because this component is not a pure indirection; we emitted markers
+ // to the stream.
+ renderNode(request, task, children, -1);
+ } else {
+ // We're now successfully past this task, and we haven't modified the
+ // context stack. We don't have to pop back to the previous task every
+ // again, so we can use the destructive recursive form.
+ renderNodeDestructive(request, task, null, children, -1);
+ }
+
+ task.keyPath = prevKeyPath;
+}
+
+function resolveDefaultProps(Component, baseProps) {
+ if (Component && Component.defaultProps) {
+ // Resolve default props. Taken from ReactElement
+ const props = assign({}, baseProps);
+ const defaultProps = Component.defaultProps;
+
+ for (const propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+
+ return props;
+ }
+
+ return baseProps;
+}
+
+function renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref) {
+ const children = renderWithHooks(request, task, keyPath, prevThenableState, type.render, props, ref);
+ const hasId = checkDidRenderIdHook();
+ const formStateCount = getFormStateCount();
+ const formStateMatchingIndex = getFormStateMatchingIndex();
+ finishFunctionComponent(request, task, keyPath, children, hasId, formStateCount, formStateMatchingIndex);
+}
+
+function renderMemo(request, task, keyPath, prevThenableState, type, props, ref) {
+ const innerType = type.type;
+ const resolvedProps = resolveDefaultProps(innerType, props);
+ renderElement(request, task, keyPath, prevThenableState, innerType, resolvedProps, ref);
+}
+
+function renderContextConsumer(request, task, keyPath, context, props) {
+
+ const render = props.children;
+
+ const newValue = readContext$1(context);
+ const newChildren = render(newValue);
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, newChildren, -1);
+ task.keyPath = prevKeyPath;
+}
+
+function renderContextProvider(request, task, keyPath, type, props) {
+ const context = type._context;
+ const value = props.value;
+ const children = props.children;
+
+ const prevKeyPath = task.keyPath;
+ task.context = pushProvider(context, value);
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, children, -1);
+ task.context = popProvider();
+ task.keyPath = prevKeyPath;
+}
+
+function renderLazyComponent(request, task, keyPath, prevThenableState, lazyComponent, props, ref) {
+ const payload = lazyComponent._payload;
+ const init = lazyComponent._init;
+ const Component = init(payload);
+ const resolvedProps = resolveDefaultProps(Component, props);
+ renderElement(request, task, keyPath, prevThenableState, Component, resolvedProps, ref);
+}
+
+function renderOffscreen(request, task, keyPath, props) {
+ const mode = props.mode;
+
+ if (mode === 'hidden') ; else {
+ // A visible Offscreen boundary is treated exactly like a fragment: a
+ // pure indirection.
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ }
+}
+
+function renderElement(request, task, keyPath, prevThenableState, type, props, ref) {
+ if (typeof type === 'function') {
+ if (shouldConstruct(type)) {
+ renderClassComponent(request, task, keyPath, type, props);
+ return;
+ } else {
+ renderIndeterminateComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+
+ if (typeof type === 'string') {
+ renderHostElement(request, task, keyPath, type, props);
+ return;
+ }
+
+ switch (type) {
+ // LegacyHidden acts the same as a fragment. This only works because we
+ // currently assume that every instance of LegacyHidden is accompanied by a
+ // host component wrapper. In the hidden mode, the host component is given a
+ // `hidden` attribute, which ensures that the initial HTML is not visible.
+ // To support the use of LegacyHidden as a true fragment, without an extra
+ // DOM node, we would have to hide the initial HTML in some other way.
+ // TODO: Delete in LegacyHidden. It's an unstable API only used in the
+ // www build. As a migration step, we could add a special prop to Offscreen
+ // that simulates the old behavior (no hiding, no change to effects).
+ case REACT_LEGACY_HIDDEN_TYPE:
+ case REACT_DEBUG_TRACING_MODE_TYPE:
+ case REACT_STRICT_MODE_TYPE:
+ case REACT_PROFILER_TYPE:
+ case REACT_FRAGMENT_TYPE:
+ {
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_OFFSCREEN_TYPE:
+ {
+ renderOffscreen(request, task, keyPath, props);
+ return;
+ }
+
+ case REACT_SUSPENSE_LIST_TYPE:
+ {
+
+ const prevKeyPath = task.keyPath;
+ task.keyPath = keyPath;
+ renderNodeDestructive(request, task, null, props.children, -1);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+
+ case REACT_SCOPE_TYPE:
+ {
+
+ throw new Error('ReactDOMServer does not yet support scope components.');
+ }
+
+ case REACT_SUSPENSE_TYPE:
+ {
+ {
+ renderSuspenseBoundary(request, task, keyPath, props);
+ }
+
+ return;
+ }
+ }
+
+ if (typeof type === 'object' && type !== null) {
+ switch (type.$$typeof) {
+ case REACT_FORWARD_REF_TYPE:
+ {
+ renderForwardRef(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_MEMO_TYPE:
+ {
+ renderMemo(request, task, keyPath, prevThenableState, type, props, ref);
+ return;
+ }
+
+ case REACT_PROVIDER_TYPE:
+ {
+ renderContextProvider(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_CONTEXT_TYPE:
+ {
+ renderContextConsumer(request, task, keyPath, type, props);
+ return;
+ }
+
+ case REACT_LAZY_TYPE:
+ {
+ renderLazyComponent(request, task, keyPath, prevThenableState, type, props);
+ return;
+ }
+ }
+ }
+
+ let info = '';
+
+ throw new Error('Element type is invalid: expected a string (for built-in ' + 'components) or a class/function (for composite components) ' + ("but got: " + (type == null ? type : typeof type) + "." + info));
+}
+
+function resumeNode(request, task, segmentId, node, childIndex) {
+ const prevReplay = task.replay;
+ const blockedBoundary = task.blockedBoundary;
+ const resumedSegment = createPendingSegment(request, 0, null, task.formatContext, false, false);
+ resumedSegment.id = segmentId;
+ resumedSegment.parentFlushed = true;
+
+ try {
+ // Convert the current ReplayTask to a RenderTask.
+ const renderTask = task;
+ renderTask.replay = null;
+ renderTask.blockedSegment = resumedSegment;
+ renderNode(request, task, node, childIndex);
+ resumedSegment.status = COMPLETED;
+
+ if (blockedBoundary === null) {
+ request.completedRootSegment = resumedSegment;
+ } else {
+ queueCompletedSegment(blockedBoundary, resumedSegment);
+
+ if (blockedBoundary.parentFlushed) {
+ request.partialBoundaries.push(blockedBoundary);
+ }
+ }
+ } finally {
+ // Restore to a ReplayTask.
+ task.replay = prevReplay;
+ task.blockedSegment = null;
+ }
+}
+
+function replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, replay) {
+ // We're replaying. Find the path to follow.
+ const replayNodes = replay.nodes;
+
+ for (let i = 0; i < replayNodes.length; i++) {
+ // Flow doesn't support refinement on tuples so we do it manually here.
+ const node = replayNodes[i];
+
+ if (keyOrIndex !== node[1]) {
+ continue;
+ }
+
+ if (node.length === 4) {
+ // Matched a replayable path.
+ // Let's double check that the component name matches as a precaution.
+ if (name !== null && name !== node[0]) {
+ throw new Error('Expected the resume to render <' + node[0] + '> in this slot but instead it rendered <' + name + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ const currentNode = task.node;
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0 // TODO check remaining slots
+ ) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ if (task.node === currentNode) {
+ // This same element suspended so we need to pop the replay we just added.
+ task.replay = replay;
+ }
+
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay;
+ } else {
+ // Let's double check that the component type matches.
+ if (type !== REACT_SUSPENSE_TYPE) {
+ const expectedType = 'Suspense';
+ throw new Error('Expected the resume to render <' + expectedType + '> in this slot but instead it rendered <' + (getComponentNameFromType(type) || 'Unknown') + '>. ' + "The tree doesn't match so React will fallback to client rendering.");
+ } // Matched a replayable path.
+
+
+ replaySuspenseBoundary(request, task, keyPath, props, node[5], node[2], node[3], node[4] === null ? [] : node[4][2], node[4] === null ? null : node[4][3]);
+ } // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+
+ replayNodes.splice(i, 1);
+ return;
+ } // We didn't find any matching nodes. We assume that this element was already
+ // rendered in the prelude and skip it.
+
+} // $FlowFixMe[missing-local-annot]
+
+function renderNodeDestructive(request, task, // The thenable state reused from the previous attempt, if any. This is almost
+// always null, except when called by retryTask.
+prevThenableState, node, childIndex) {
+ {
+ return renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex);
+ }
+} // This function by it self renders a node and consumes the task by mutating it
+// to update the current execution state.
+
+
+function renderNodeDestructiveImpl(request, task, prevThenableState, node, childIndex) {
+ if (task.replay !== null && typeof task.replay.slots === 'number') {
+ // TODO: Figure out a cheaper place than this hot path to do this check.
+ const resumeSegmentID = task.replay.slots;
+ resumeNode(request, task, resumeSegmentID, node, childIndex);
+ return;
+ } // Stash the node we're working on. We'll pick up from this task in case
+ // something suspends.
+
+
+ task.node = node;
+ task.childIndex = childIndex; // Handle object types
+
+ if (typeof node === 'object' && node !== null) {
+ switch (node.$$typeof) {
+ case REACT_ELEMENT_TYPE:
+ {
+ const element = node;
+ const type = element.type;
+ const key = element.key;
+ const props = element.props;
+ const ref = element.ref;
+ const name = getComponentNameFromType(type);
+ const keyOrIndex = key == null ? childIndex === -1 ? 0 : childIndex : key;
+ const keyPath = [task.keyPath, name, keyOrIndex];
+
+ if (task.replay !== null) {
+ replayElement(request, task, keyPath, prevThenableState, name, keyOrIndex, childIndex, type, props, ref, task.replay); // No matches found for this node. We assume it's already emitted in the
+ // prelude and skip it during the replay.
+ } else {
+ // We're doing a plain render.
+ renderElement(request, task, keyPath, prevThenableState, type, props, ref);
+ }
+
+ return;
+ }
+
+ case REACT_PORTAL_TYPE:
+ throw new Error('Portals are not currently supported by the server renderer. ' + 'Render them conditionally so that they only appear on the client render.');
+
+ case REACT_LAZY_TYPE:
+ {
+ const lazyNode = node;
+ const payload = lazyNode._payload;
+ const init = lazyNode._init;
+ let resolvedNode;
+
+ {
+ resolvedNode = init(payload);
+ }
+
+ renderNodeDestructive(request, task, null, resolvedNode, childIndex);
+ return;
+ }
+ }
+
+ if (isArray(node)) {
+ renderChildrenArray(request, task, node, childIndex);
+ return;
+ }
+
+ const iteratorFn = getIteratorFn(node);
+
+ if (iteratorFn) {
+
+ const iterator = iteratorFn.call(node);
+
+ if (iterator) {
+ // We need to know how many total children are in this set, so that we
+ // can allocate enough id slots to acommodate them. So we must exhaust
+ // the iterator before we start recursively rendering the children.
+ // TODO: This is not great but I think it's inherent to the id
+ // generation algorithm.
+ let step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that.
+
+ if (!step.done) {
+ const children = [];
+
+ do {
+ children.push(step.value);
+ step = iterator.next();
+ } while (!step.done);
+
+ renderChildrenArray(request, task, children, childIndex);
+ return;
+ }
+
+ return;
+ }
+ } // Usables are a valid React node type. When React encounters a Usable in
+ // a child position, it unwraps it using the same algorithm as `use`. For
+ // example, for promises, React will throw an exception to unwind the
+ // stack, then replay the component once the promise resolves.
+ //
+ // A difference from `use` is that React will keep unwrapping the value
+ // until it reaches a non-Usable type.
+ //
+ // e.g. Usable>> should resolve to T
+
+
+ const maybeUsable = node;
+
+ if (typeof maybeUsable.then === 'function') {
+ const thenable = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, unwrapThenable(thenable), childIndex);
+ }
+
+ if (maybeUsable.$$typeof === REACT_CONTEXT_TYPE || maybeUsable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
+ const context = maybeUsable;
+ return renderNodeDestructiveImpl(request, task, null, readContext$1(context), childIndex);
+ } // $FlowFixMe[method-unbinding]
+
+
+ const childString = Object.prototype.toString.call(node);
+ throw new Error("Objects are not valid as a React child (found: " + (childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString) + "). " + 'If you meant to render a collection of children, use an array ' + 'instead.');
+ }
+
+ if (typeof node === 'string') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+
+ if (typeof node === 'number') {
+ const segment = task.blockedSegment;
+
+ if (segment === null) ; else {
+ segment.lastPushedText = pushTextInstance(segment.chunks, '' + node, request.renderState, segment.lastPushedText);
+ }
+
+ return;
+ }
+}
+
+function replayFragment(request, task, children, childIndex) {
+ // If we're supposed follow this array, we'd expect to see a ReplayNode matching
+ // this fragment.
+ const replay = task.replay;
+ const replayNodes = replay.nodes;
+
+ for (let j = 0; j < replayNodes.length; j++) {
+ const node = replayNodes[j];
+
+ if (node[1] !== childIndex) {
+ continue;
+ } // Matched a replayable path.
+
+
+ const childNodes = node[2];
+ const childSlots = node[3];
+ task.replay = {
+ nodes: childNodes,
+ slots: childSlots,
+ pendingTasks: 1
+ };
+
+ try {
+ renderChildrenArray(request, task, children, -1);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ } catch (x) {
+ if (typeof x === 'object' && x !== null && (x === SuspenseException || typeof x.then === 'function')) {
+ // Suspend
+ throw x;
+ }
+
+ task.replay.pendingTasks--; // Unlike regular render, we don't terminate the siblings if we error
+ // during a replay. That's because this component didn't actually error
+ // in the original prerender. What's unable to complete is the child
+ // replay nodes which might be Suspense boundaries which are able to
+ // absorb the error and we can still continue with siblings.
+ // This is an error, stash the component stack if it is null.
+
+ erroredReplay(request, task.blockedBoundary, x, childNodes, childSlots);
+ }
+
+ task.replay = replay; // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ replayNodes.splice(j, 1);
+ break;
+ }
+}
+
+function renderChildrenArray(request, task, children, childIndex) {
+ const prevKeyPath = task.keyPath;
+
+ if (childIndex !== -1) {
+ task.keyPath = [task.keyPath, 'Fragment', childIndex];
+
+ if (task.replay !== null) {
+ replayFragment(request, // $FlowFixMe: Refined.
+ task, children, childIndex);
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ const prevTreeContext = task.treeContext;
+ const totalChildren = children.length;
+
+ if (task.replay !== null) {
+ // Replay
+ // First we need to check if we have any resume slots at this level.
+ const resumeSlots = task.replay.slots;
+
+ if (resumeSlots !== null && typeof resumeSlots === 'object') {
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ const resumeSegmentID = resumeSlots[i]; // TODO: If this errors we should still continue with the next sibling.
+
+ if (typeof resumeSegmentID === 'number') {
+ resumeNode(request, task, resumeSegmentID, node, i); // We finished rendering this node, so now we can consume this
+ // slot. This must happen after in case we rerender this task.
+
+ delete resumeSlots[i];
+ } else {
+ renderNode(request, task, node, i);
+ }
+ }
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+ return;
+ }
+ }
+
+ for (let i = 0; i < totalChildren; i++) {
+ const node = children[i];
+ task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); // We need to use the non-destructive form so that we can safely pop back
+ // up and render the sibling if something suspends.
+
+ renderNode(request, task, node, i);
+ } // Because this context is always set right before rendering every child, we
+ // only need to reset it to the previous value at the very end.
+
+
+ task.treeContext = prevTreeContext;
+ task.keyPath = prevKeyPath;
+}
+
+function spawnNewSuspendedReplayTask(request, task, thenableState, x) {
+ const newTask = createReplayTask(request, thenableState, task.replay, task.node, task.childIndex, task.blockedBoundary, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+}
+
+function spawnNewSuspendedRenderTask(request, task, thenableState, x) {
+ // Something suspended, we'll need to create a new segment and resolve it later.
+ const segment = task.blockedSegment;
+ const insertionIndex = segment.chunks.length;
+ const newSegment = createPendingSegment(request, insertionIndex, null, task.formatContext, // Adopt the parent segment's leading text embed
+ segment.lastPushedText, // Assume we are text embedded at the trailing edge
+ true);
+ segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it
+
+ segment.lastPushedText = false;
+ const newTask = createRenderTask(request, thenableState, task.node, task.childIndex, task.blockedBoundary, newSegment, task.abortSet, task.keyPath, task.formatContext, task.legacyContext, task.context, task.treeContext);
+
+ const ping = newTask.ping;
+ x.then(ping, ping);
+} // This is a non-destructive form of rendering a node. If it suspends it spawns
+// a new task and restores the context of this task to what it was before.
+
+
+function renderNode(request, task, node, childIndex) {
+ // Snapshot the current context in case something throws to interrupt the
+ // process.
+ const previousFormatContext = task.formatContext;
+ const previousLegacyContext = task.legacyContext;
+ const previousContext = task.context;
+ const previousKeyPath = task.keyPath;
+ const previousTreeContext = task.treeContext;
+
+ let x; // Store how much we've pushed at this point so we can reset it in case something
+ // suspended partially through writing something.
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ // Replay
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState();
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedReplayTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ } // TODO: Abort any undiscovered Suspense boundaries in the ReplayNode.
+
+ }
+ } else {
+ // Render
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ return renderNodeDestructive(request, task, null, node, childIndex);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ const wakeable = x;
+ const thenableState = getThenableStateAfterSuspending();
+ spawnNewSuspendedRenderTask(request, // $FlowFixMe: Refined.
+ task, thenableState, wakeable); // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+
+ return;
+ }
+ }
+ }
+ } // Restore the context. We assume that this will be restored by the inner
+ // functions in case nothing throws so we don't use "finally" here.
+
+
+ task.formatContext = previousFormatContext;
+ task.legacyContext = previousLegacyContext;
+ task.context = previousContext;
+ task.keyPath = previousKeyPath;
+ task.treeContext = previousTreeContext; // Restore all active ReactContexts to what they were before.
+
+ switchContext(previousContext);
+ // Let's terminate the rest of the tree and don't render any siblings.
+
+
+ throw x;
+}
+
+function erroredReplay(request, boundary, error, replayNodes, resumeSlots) {
+ // Erroring during a replay doesn't actually cause an error by itself because
+ // that component has already rendered. What causes the error is the resumable
+ // points that we did not yet finish which will be below the point of the reset.
+ // For example, if we're replaying a path to a Suspense boundary that is not done
+ // that doesn't error the parent Suspense boundary.
+ // This might be a bit strange that the error in a parent gets thrown at a child.
+ // We log it only once and reuse the digest.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ abortRemainingReplayNodes(request, boundary, replayNodes, resumeSlots, error, errorDigest);
+}
+
+function erroredTask(request, boundary, error) {
+ // Report the error to a global handler.
+ let errorDigest;
+
+ {
+ errorDigest = logRecoverableError(request, error);
+ }
+
+ if (boundary === null) {
+ fatalError(request, error);
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+ // so we can flush it, if the parent already flushed.
+
+
+ if (boundary.parentFlushed) {
+ // We don't have a preference where in the queue this goes since it's likely
+ // to error on the client anyway. However, intentionally client-rendered
+ // boundaries should be flushed earlier so that they can start on the client.
+ // We reuse the same queue for errors.
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function abortTaskSoft(task) {
+ // This aborts task without aborting the parent boundary that it blocks.
+ // It's used for when we didn't need this task to complete the tree.
+ // If task was needed, then it should use abortTask instead.
+ const request = this;
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ finishedTask(request, boundary, segment);
+ }
+}
+
+function abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest) {
+ const resumedBoundary = createSuspenseBoundary(request, new Set());
+ resumedBoundary.parentFlushed = true; // We restore the same id of this boundary as was used during prerender.
+
+ resumedBoundary.rootSegmentID = rootSegmentID;
+ resumedBoundary.status = CLIENT_RENDERED;
+ resumedBoundary.errorDigest = errorDigest;
+
+ if (resumedBoundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(resumedBoundary);
+ }
+}
+
+function abortRemainingReplayNodes(request, boundary, nodes, slots, error, errorDigest) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+
+ if (node.length === 4) {
+ abortRemainingReplayNodes(request, boundary, node[2], node[3], error, errorDigest);
+ } else {
+ const boundaryNode = node;
+ const rootSegmentID = boundaryNode[5];
+ abortRemainingSuspenseBoundary(request, rootSegmentID, error, errorDigest);
+ }
+ } // Empty the set, since we've cleared it now.
+
+
+ nodes.length = 0;
+
+ if (slots !== null) {
+ // We had something still to resume in the parent boundary. We must trigger
+ // the error on the parent boundary since it's not able to complete.
+ if (boundary === null) {
+ throw new Error('We should not have any resumable nodes in the shell. ' + 'This is a bug in React.');
+ } else if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = errorDigest;
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // Empty the set
+
+
+ if (typeof slots === 'object') {
+ for (const index in slots) {
+ delete slots[index];
+ }
+ }
+ }
+}
+
+function abortTask(task, request, error) {
+ // This aborts the task and aborts the parent that it blocks, putting it into
+ // client rendered mode.
+ const boundary = task.blockedBoundary;
+ const segment = task.blockedSegment;
+
+ if (segment !== null) {
+ segment.status = ABORTED;
+ }
+
+ if (boundary === null) {
+ if (request.status !== CLOSING && request.status !== CLOSED) {
+ const replay = task.replay;
+
+ if (replay === null) {
+ // We didn't complete the root so we have nothing to show. We can close
+ // the request;
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ return;
+ } else {
+ // If the shell aborts during a replay, that's not a fatal error. Instead
+ // we should be able to recover by client rendering all the root boundaries in
+ // the ReplaySet.
+ replay.pendingTasks--;
+
+ if (replay.pendingTasks === 0 && replay.nodes.length > 0) {
+ const errorDigest = logRecoverableError(request, error);
+ abortRemainingReplayNodes(request, null, replay.nodes, replay.slots, error, errorDigest);
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ }
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status !== CLIENT_RENDERED) {
+ boundary.status = CLIENT_RENDERED;
+ boundary.errorDigest = logRecoverableError(request, error);
+
+ if (boundary.parentFlushed) {
+ request.clientRenderedBoundaries.push(boundary);
+ }
+ } // If this boundary was still pending then we haven't already cancelled its fallbacks.
+ // We'll need to abort the fallbacks, which will also error that parent boundary.
+
+
+ boundary.fallbackAbortableTasks.forEach(fallbackTask => abortTask(fallbackTask, request, error));
+ boundary.fallbackAbortableTasks.clear();
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeShell(request) {
+ if (request.trackedPostpones === null) {
+ // We only emit early preloads on shell completion for renders. For prerenders
+ // we wait for the entire Request to finish because we are not responding to a
+ // live request and can wait for as much data as possible.
+ // we should only be calling completeShell when the shell is complete so we
+ // just use a literal here
+ const shellComplete = true;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ } // We have completed the shell so the shell can't error anymore.
+
+
+ request.onShellError = noop;
+ const onShellReady = request.onShellReady;
+ onShellReady();
+} // I extracted this function out because we want to ensure we consistently emit preloads before
+// transitioning to the next request stage and this transition can happen in multiple places in this
+// implementation.
+
+
+function completeAll(request) {
+ // During a render the shell must be complete if the entire request is finished
+ // however during a Prerender it is possible that the shell is incomplete because
+ // it postponed. We cannot use rootPendingTasks in the prerender case because
+ // those hit zero even when the shell postpones. Instead we look at the completedRootSegment
+ const shellComplete = request.trackedPostpones === null ? // Render, we assume it is completed
+ true : // Prerender Request, we use the state of the root segment
+ request.completedRootSegment === null || request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+ const onAllReady = request.onAllReady;
+ onAllReady();
+}
+
+function queueCompletedSegment(boundary, segment) {
+ if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) {
+ // This is an empty segment. There's nothing to write, so we can instead transfer the ID
+ // to the child. That way any existing references point to the child.
+ const childSegment = segment.children[0];
+ childSegment.id = segment.id;
+ childSegment.parentFlushed = true;
+
+ if (childSegment.status === COMPLETED) {
+ queueCompletedSegment(boundary, childSegment);
+ }
+ } else {
+ const completedSegments = boundary.completedSegments;
+ completedSegments.push(segment);
+ }
+}
+
+function finishedTask(request, boundary, segment) {
+ if (boundary === null) {
+ if (segment !== null && segment.parentFlushed) {
+ if (request.completedRootSegment !== null) {
+ throw new Error('There can only be one root segment. This is a bug in React.');
+ }
+
+ request.completedRootSegment = segment;
+ }
+
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+ } else {
+ boundary.pendingTasks--;
+
+ if (boundary.status === CLIENT_RENDERED) ; else if (boundary.pendingTasks === 0) {
+ if (boundary.status === PENDING) {
+ boundary.status = COMPLETED;
+ } // This must have been the last segment we were waiting on. This boundary is now complete.
+
+
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent segment already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ }
+ }
+
+ if (boundary.parentFlushed) {
+ // The segment might be part of a segment that didn't flush yet, but if the boundary's
+ // parent flushed, we need to schedule the boundary to be emitted.
+ request.completedBoundaries.push(boundary);
+ } // We can now cancel any pending task on the fallback since we won't need to show it anymore.
+ // This needs to happen after we read the parentFlushed flags because aborting can finish
+ // work which can trigger user code, which can start flushing, which can change those flags.
+ // If the boundary was POSTPONED, we still need to finish the fallback first.
+
+
+ if (boundary.status === COMPLETED) {
+ boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
+ boundary.fallbackAbortableTasks.clear();
+ }
+ } else {
+ if (segment !== null && segment.parentFlushed) {
+ // Our parent already flushed, so we need to schedule this segment to be emitted.
+ // If it is a segment that was aborted, we'll write other content instead so we don't need
+ // to emit it.
+ if (segment.status === COMPLETED) {
+ queueCompletedSegment(boundary, segment);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length === 1) {
+ // This is the first time since we last flushed that we completed anything.
+ // We can schedule this boundary to emit its partially completed segments early
+ // in case the parent has already been flushed.
+ if (boundary.parentFlushed) {
+ request.partialBoundaries.push(boundary);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+}
+
+function retryTask(request, task) {
+ {
+ const blockedBoundary = task.blockedBoundary;
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, blockedBoundary ? blockedBoundary.resources : null);
+ }
+
+ const segment = task.blockedSegment;
+
+ if (segment === null) {
+ retryReplayTask(request, // $FlowFixMe: Refined.
+ task);
+ } else {
+ retryRenderTask(request, // $FlowFixMe: Refined.
+ task, segment);
+ }
+}
+
+function retryRenderTask(request, task, segment) {
+ if (segment.status !== PENDING) {
+ // We completed this by other means before we had a chance to retry it.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ const childrenLength = segment.children.length;
+ const chunkLength = segment.chunks.length;
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+ pushSegmentFinale(segment.chunks, request.renderState, segment.lastPushedText, segment.textEmbedded);
+ task.abortSet.delete(task);
+ segment.status = COMPLETED;
+ finishedTask(request, task.blockedBoundary, segment);
+ } catch (thrownValue) {
+ resetHooksState(); // Reset the write pointers to where we started.
+
+ segment.children.length = childrenLength;
+ segment.chunks.length = chunkLength;
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.abortSet.delete(task);
+ segment.status = ERRORED;
+ erroredTask(request, task.blockedBoundary, x);
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function retryReplayTask(request, task) {
+ if (task.replay.pendingTasks === 0) {
+ // There are no pending tasks working on this set, so we must have aborted.
+ return;
+ } // We restore the context to what it was when we suspended.
+ // We don't restore it after we leave because it's likely that we'll end up
+ // needing a very similar context soon again.
+
+
+ switchContext(task.context);
+
+ try {
+ // We call the destructive form that mutates this task. That way if something
+ // suspends again, we can reuse the same task instead of spawning a new one.
+ // Reset the task's thenable state before continuing, so that if a later
+ // component suspends we can reuse the same task object. If the same
+ // component suspends again, the thenable state will be restored.
+ const prevThenableState = task.thenableState;
+ task.thenableState = null;
+ renderNodeDestructive(request, task, prevThenableState, task.node, task.childIndex);
+
+ if (task.replay.pendingTasks === 1 && task.replay.nodes.length > 0) {
+ throw new Error("Couldn't find all resumable slots by key/index during replaying. " + "The tree doesn't match so React will fallback to client rendering.");
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ finishedTask(request, task.blockedBoundary, null);
+ } catch (thrownValue) {
+ resetHooksState();
+ const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical
+ // reasons, the rest of the Suspense implementation expects the thrown
+ // value to be a thenable, because before `use` existed that was the
+ // (unstable) API for suspending. This implementation detail can change
+ // later, once we deprecate the old API in favor of `use`.
+ getSuspendedThenable() : thrownValue;
+
+ if (typeof x === 'object' && x !== null) {
+ // $FlowFixMe[method-unbinding]
+ if (typeof x.then === 'function') {
+ // Something suspended again, let's pick it back up later.
+ const ping = task.ping;
+ x.then(ping, ping);
+ task.thenableState = getThenableStateAfterSuspending();
+ return;
+ }
+ }
+
+ task.replay.pendingTasks--;
+ task.abortSet.delete(task);
+ erroredReplay(request, task.blockedBoundary, x, task.replay.nodes, task.replay.slots);
+ request.pendingRootTasks--;
+
+ if (request.pendingRootTasks === 0) {
+ completeShell(request);
+ }
+
+ request.allPendingTasks--;
+
+ if (request.allPendingTasks === 0) {
+ completeAll(request);
+ }
+
+ return;
+ } finally {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, null);
+ }
+ }
+}
+
+function performWork(request) {
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ const prevContext = getActiveContext();
+ const prevDispatcher = ReactCurrentDispatcher.current;
+ ReactCurrentDispatcher.current = HooksDispatcher;
+ let prevCacheDispatcher;
+
+ {
+ prevCacheDispatcher = ReactCurrentCache.current;
+ ReactCurrentCache.current = DefaultCacheDispatcher;
+ }
+
+ const prevRequest = currentRequest;
+ currentRequest = request;
+
+ const prevResumableState = currentResumableState;
+ setCurrentResumableState(request.resumableState);
+
+ try {
+ const pingedTasks = request.pingedTasks;
+ let i;
+
+ for (i = 0; i < pingedTasks.length; i++) {
+ const task = pingedTasks[i];
+ retryTask(request, task);
+ }
+
+ pingedTasks.splice(0, i);
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ } finally {
+ setCurrentResumableState(prevResumableState);
+ ReactCurrentDispatcher.current = prevDispatcher;
+
+ {
+ ReactCurrentCache.current = prevCacheDispatcher;
+ }
+
+ if (prevDispatcher === HooksDispatcher) {
+ // This means that we were in a reentrant work loop. This could happen
+ // in a renderer that supports synchronous work like renderToString,
+ // when it's called from within another renderer.
+ // Normally we don't bother switching the contexts to their root/default
+ // values when leaving because we'll likely need the same or similar
+ // context again. However, when we're inside a synchronous loop like this
+ // we'll to restore the context to what it was before returning.
+ switchContext(prevContext);
+ }
+
+ currentRequest = prevRequest;
+ }
+}
+
+function flushSubtree(request, destination, segment) {
+ segment.parentFlushed = true;
+
+ switch (segment.status) {
+ case PENDING:
+ {
+ // We're emitting a placeholder for this segment to be filled in later.
+ // Therefore we'll need to assign it an ID - to refer to it by.
+ segment.id = request.nextSegmentId++; // Fallthrough
+ }
+
+ case POSTPONED:
+ {
+ const segmentID = segment.id; // When this segment finally completes it won't be embedded in text since it will flush separately
+
+ segment.lastPushedText = false;
+ segment.textEmbedded = false;
+ return writePlaceholder(destination, request.renderState, segmentID);
+ }
+
+ case COMPLETED:
+ {
+ segment.status = FLUSHED;
+ let r = true;
+ const chunks = segment.chunks;
+ let chunkIdx = 0;
+ const children = segment.children;
+
+ for (let childIdx = 0; childIdx < children.length; childIdx++) {
+ const nextChild = children[childIdx]; // Write all the chunks up until the next child.
+
+ for (; chunkIdx < nextChild.index; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ r = flushSegment(request, destination, nextChild);
+ } // Finally just write all the remaining chunks
+
+
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
+ writeChunk(destination, chunks[chunkIdx]);
+ }
+
+ if (chunkIdx < chunks.length) {
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
+ }
+
+ return r;
+ }
+
+ default:
+ {
+ throw new Error('Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.');
+ }
+ }
+}
+
+function flushSegment(request, destination, segment) {
+ const boundary = segment.boundary;
+
+ if (boundary === null) {
+ // Not a suspense boundary.
+ return flushSubtree(request, destination, segment);
+ }
+
+ boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to
+ // emit the content or the fallback now.
+
+ if (boundary.status === CLIENT_RENDERED) {
+ // Emit a client rendered suspense boundary wrapper.
+ // We never queue the inner boundary so we'll never emit its content or partial segments.
+ writeStartClientRenderedSuspenseBoundary(destination, request.renderState, boundary.errorDigest); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndClientRenderedSuspenseBoundary(destination);
+ } else if (boundary.status !== COMPLETED) {
+ if (boundary.status === PENDING) {
+ // For pending boundaries we lazily assign an ID to the boundary
+ // and root segment.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ }
+
+ if (boundary.completedSegments.length > 0) {
+ // If this is at least partially complete, we can queue it to be partially emitted early.
+ request.partialBoundaries.push(boundary);
+ } // This boundary is still loading. Emit a pending suspense boundary wrapper.
+
+
+ const id = boundary.rootSegmentID;
+ writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else if (boundary.byteSize > request.progressiveChunkSize) {
+ // This boundary is large and will be emitted separately so that we can progressively show
+ // other content. We add it to the queue during the flush because we have to ensure that
+ // the parent flushes first so that there's something to inject it into.
+ // We also have to make sure that it's emitted into the queue in a deterministic slot.
+ // I.e. we can't insert it here when it completes.
+ // Assign an ID to refer to the future content by.
+ boundary.rootSegmentID = request.nextSegmentId++;
+ request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper.
+
+ writeStartPendingSuspenseBoundary(destination, request.renderState, boundary.rootSegmentID); // Flush the fallback.
+
+ flushSubtree(request, destination, segment);
+ return writeEndPendingSuspenseBoundary(destination);
+ } else {
+ {
+ hoistResources(request.renderState, boundary.resources);
+ } // We can inline this boundary's content as a complete boundary.
+
+
+ writeStartCompletedSuspenseBoundary(destination);
+ const completedSegments = boundary.completedSegments;
+
+ if (completedSegments.length !== 1) {
+ throw new Error('A previously unvisited boundary must have exactly one root segment. This is a bug in React.');
+ }
+
+ const contentSegment = completedSegments[0];
+ flushSegment(request, destination, contentSegment);
+ return writeEndCompletedSuspenseBoundary(destination);
+ }
+}
+
+function flushClientRenderedBoundary(request, destination, boundary) {
+ return writeClientRenderBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack);
+}
+
+function flushSegmentContainer(request, destination, segment) {
+ writeStartSegment(destination, request.renderState, segment.parentFormatContext, segment.id);
+ flushSegment(request, destination, segment);
+ return writeEndSegment(destination, segment.parentFormatContext);
+}
+
+function flushCompletedBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+ flushPartiallyCompletedSegment(request, destination, boundary, segment);
+ }
+
+ completedSegments.length = 0;
+
+ {
+ writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+
+ return writeCompletedBoundaryInstruction(destination, request.resumableState, request.renderState, boundary.rootSegmentID, boundary.resources);
+}
+
+function flushPartialBoundary(request, destination, boundary) {
+ {
+ setCurrentlyRenderingBoundaryResourcesTarget(request.renderState, boundary.resources);
+ }
+
+ const completedSegments = boundary.completedSegments;
+ let i = 0;
+
+ for (; i < completedSegments.length; i++) {
+ const segment = completedSegments[i];
+
+ if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) {
+ i++;
+ completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority
+ // might want to write later.
+
+ return false;
+ }
+ }
+
+ completedSegments.splice(0, i);
+
+ {
+ // The way this is structured we only write resources for partial boundaries
+ // if there is no backpressure. Later before we complete the boundary we
+ // will write resources regardless of backpressure before we emit the
+ // completion instruction
+ return writeResourcesForBoundary(destination, boundary.resources, request.renderState);
+ }
+}
+
+function flushPartiallyCompletedSegment(request, destination, boundary, segment) {
+ if (segment.status === FLUSHED) {
+ // We've already flushed this inline.
+ return true;
+ }
+
+ const segmentID = segment.id;
+
+ if (segmentID === -1) {
+ // This segment wasn't previously referred to. This happens at the root of
+ // a boundary. We make kind of a leap here and assume this is the root.
+ const rootSegmentID = segment.id = boundary.rootSegmentID;
+
+ if (rootSegmentID === -1) {
+ throw new Error('A root segment ID must have been assigned by now. This is a bug in React.');
+ }
+
+ return flushSegmentContainer(request, destination, segment);
+ } else if (segmentID === boundary.rootSegmentID) {
+ // When we emit postponed boundaries, we might have assigned the ID already
+ // but it's still the root segment so we can't inject it into the parent yet.
+ return flushSegmentContainer(request, destination, segment);
+ } else {
+ flushSegmentContainer(request, destination, segment);
+ return writeCompletedSegmentInstruction(destination, request.resumableState, request.renderState, segmentID);
+ }
+}
+
+function flushCompletedQueues(request, destination) {
+ beginWriting();
+
+ try {
+ // The structure of this is to go through each queue one by one and write
+ // until the sink tells us to stop. When we should stop, we still finish writing
+ // that item fully and then yield. At that point we remove the already completed
+ // items up until the point we completed them.
+ let i;
+ const completedRootSegment = request.completedRootSegment;
+
+ if (completedRootSegment !== null) {
+ if (completedRootSegment.status === POSTPONED) {
+ // We postponed the root, so we write nothing.
+ return;
+ } else if (request.pendingRootTasks === 0) {
+ if (enableFloat) {
+ writePreamble(destination, request.resumableState, request.renderState, request.allPendingTasks === 0 && request.trackedPostpones === null);
+ }
+
+ flushSegment(request, destination, completedRootSegment);
+ request.completedRootSegment = null;
+ writeCompletedRoot(destination, request.renderState, request.resumableState);
+ } else {
+ // We haven't flushed the root yet so we don't need to check any other branches further down
+ return;
+ }
+ }
+
+ if (enableFloat) {
+ writeHoistables(destination, request.resumableState, request.renderState);
+ } // We emit client rendering instructions for already emitted boundaries first.
+ // This is so that we can signal to the client to start client rendering them as
+ // soon as possible.
+
+
+ const clientRenderedBoundaries = request.clientRenderedBoundaries;
+
+ for (i = 0; i < clientRenderedBoundaries.length; i++) {
+ const boundary = clientRenderedBoundaries[i];
+
+ if (!flushClientRenderedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ clientRenderedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries
+ // that are completely done since we can actually show them, than it is to emit
+ // any individual segments from a partially complete boundary.
+
+ const completedBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < completedBoundaries.length; i++) {
+ const boundary = completedBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ completedBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before
+ // we continue with lower priorities.
+
+ completeWriting(destination);
+ beginWriting(destination); // TODO: Here we'll emit data used by hydration.
+ // Next we emit any segments of any boundaries that are partially complete
+ // but not deeply complete.
+
+ const partialBoundaries = request.partialBoundaries;
+
+ for (i = 0; i < partialBoundaries.length; i++) {
+ const boundary = partialBoundaries[i];
+
+ if (!flushPartialBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ partialBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had
+ // boundaries added to it in case they were too larged to be inlined.
+ // New ones might be added in this loop.
+
+ const largeBoundaries = request.completedBoundaries;
+
+ for (i = 0; i < largeBoundaries.length; i++) {
+ const boundary = largeBoundaries[i];
+
+ if (!flushCompletedBoundary(request, destination, boundary)) {
+ request.destination = null;
+ i++;
+ largeBoundaries.splice(0, i);
+ return;
+ }
+ }
+
+ largeBoundaries.splice(0, i);
+ } finally {
+ if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because
+ // either they have pending task or they're complete.
+ ) {
+ request.flushScheduled = false;
+
+ {
+ // We write the trailing tags but only if don't have any data to resume.
+ // If we need to resume we'll write the postamble in the resume instead.
+ {
+ writePostamble(destination, request.resumableState);
+ }
+ }
+
+ completeWriting(destination);
+ flushBuffered(destination);
+
+
+ close(destination); // We need to stop flowing now because we do not want any async contexts which might call
+ // float methods to initiate any flushes after this point
+
+ stopFlowing(request);
+ } else {
+ completeWriting(destination);
+ flushBuffered(destination);
+ }
+ }
+}
+
+function startWork(request) {
+ request.flushScheduled = request.destination !== null;
+
+ {
+ scheduleWork(() => requestStorage.run(request, performWork, request));
+ }
+
+ if (request.trackedPostpones === null) {
+ // this is either a regular render or a resume. For regular render we want
+ // to call emitEarlyPreloads after the first performWork because we want
+ // are responding to a live request and need to balance sending something early
+ // (i.e. don't want for the shell to finish) but we need something to send.
+ // The only implementation of this is for DOM at the moment and during resumes nothing
+ // actually emits but the code paths here are the same.
+ // During a prerender we don't want to be too aggressive in emitting early preloads
+ // because we aren't responding to a live request and we can wait for the prerender to
+ // postpone before we emit anything.
+ {
+ scheduleWork(() => requestStorage.run(request, enqueueEarlyPreloadsAfterInitialWork, request));
+ }
+ }
+}
+
+function enqueueEarlyPreloadsAfterInitialWork(request) {
+ const shellComplete = request.pendingRootTasks === 0;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+
+function enqueueFlush(request) {
+ if (request.flushScheduled === false && // If there are pinged tasks we are going to flush anyway after work completes
+ request.pingedTasks.length === 0 && // If there is no destination there is nothing we can flush to. A flush will
+ // happen when we start flowing again
+ request.destination !== null) {
+ request.flushScheduled = true;
+ scheduleWork(() => {
+ // We need to existence check destination again here because it might go away
+ // in between the enqueueFlush call and the work execution
+ const destination = request.destination;
+
+ if (destination) {
+ flushCompletedQueues(request, destination);
+ } else {
+ request.flushScheduled = false;
+ }
+ });
+ }
+} // This function is intented to only be called during the pipe function for the Node builds.
+// The reason we need this is because `renderToPipeableStream` is the only API which allows
+// you to start flowing before the shell is complete and we've had a chance to emit early
+// preloads already. This is really just defensive programming to ensure that we give hosts an
+// opportunity to flush early preloads before streaming begins in case they are in an environment
+// that only supports a single call to emitEarlyPreloads like the DOM renderers. It's unfortunate
+// to put this Node only function directly in ReactFizzServer but it'd be more ackward to factor it
+// by moving the implementation into ReactServerStreamConfigNode and even then we may not be able to
+// eliminate all the wasted branching.
+
+
+function prepareForStartFlowingIfBeforeAllReady(request) {
+ const shellComplete = request.trackedPostpones === null ? // Render Request, we define shell complete by the pending root tasks
+ request.pendingRootTasks === 0 : // Prerender Request, we define shell complete by completedRootSegemtn
+ request.completedRootSegment === null ? request.pendingRootTasks === 0 : request.completedRootSegment.status !== POSTPONED;
+ emitEarlyPreloads(request.renderState, request.resumableState, shellComplete);
+}
+function startFlowing(request, destination) {
+ if (request.status === CLOSING) {
+ request.status = CLOSED;
+ closeWithError(destination, request.fatalError);
+ return;
+ }
+
+ if (request.status === CLOSED) {
+ return;
+ }
+
+ if (request.destination !== null) {
+ // We're already flowing.
+ return;
+ }
+
+ request.destination = destination;
+
+ try {
+ flushCompletedQueues(request, destination);
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function stopFlowing(request) {
+ request.destination = null;
+} // This is called to early terminate a request. It puts all pending boundaries in client rendered state.
+
+function abort(request, reason) {
+ try {
+ const abortableTasks = request.abortableTasks;
+
+ if (abortableTasks.size > 0) {
+ const error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason;
+ abortableTasks.forEach(task => abortTask(task, request, error));
+ abortableTasks.clear();
+ }
+
+ if (request.destination !== null) {
+ flushCompletedQueues(request, request.destination);
+ }
+ } catch (error) {
+ logRecoverableError(request, error);
+ fatalError(request, error);
+ }
+}
+function flushResources(request) {
+ enqueueFlush(request);
+}
+function getFormState(request) {
+ return request.formState;
+}
+function getResumableState(request) {
+ return request.resumableState;
+}
+function getRenderState(request) {
+ return request.renderState;
+}
+
+function createDrainHandler(destination, request) {
+ return () => startFlowing(request, destination);
+}
+
+function createCancelHandler(request, reason) {
+ return () => {
+ stopFlowing(request); // eslint-disable-next-line react-internal/prod-error-codes
+
+ abort(request, new Error(reason));
+ };
+}
+
+function createRequestImpl(children, options) {
+ const resumableState = createResumableState(options ? options.identifierPrefix : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.bootstrapScriptContent : undefined, options ? options.bootstrapScripts : undefined, options ? options.bootstrapModules : undefined);
+ return createRequest(children, resumableState, createRenderState(resumableState, options ? options.nonce : undefined, options ? options.unstable_externalRuntimeSrc : undefined, options ? options.importMap : undefined, options ? options.onHeaders : undefined, options ? options.maxHeadersLength : undefined), createRootFormatContext(options ? options.namespaceURI : undefined), options ? options.progressiveChunkSize : undefined, options ? options.onError : undefined, options ? options.onAllReady : undefined, options ? options.onShellReady : undefined, options ? options.onShellError : undefined, undefined, options ? options.onPostpone : undefined, options ? options.formState : undefined);
+}
+
+function renderToPipeableStream(children, options) {
+ const request = createRequestImpl(children, options);
+ let hasStartedFlowing = false;
+ startWork(request);
+ return {
+ pipe(destination) {
+ if (hasStartedFlowing) {
+ throw new Error('React currently only supports piping to one writable stream.');
+ }
+
+ hasStartedFlowing = true;
+ prepareForStartFlowingIfBeforeAllReady(request);
+ startFlowing(request, destination);
+ destination.on('drain', createDrainHandler(destination, request));
+ destination.on('error', createCancelHandler(request, 'The destination stream errored while writing data.'));
+ destination.on('close', createCancelHandler(request, 'The destination stream closed early.'));
+ return destination;
+ },
+
+ abort(reason) {
+ abort(request, reason);
+ }
+
+ };
+}
+
+exports.renderToPipeableStream = renderToPipeableStream;
+exports.version = ReactVersion;
\ No newline at end of file
diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.production.min.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.production.min.js
index b4d5502147a07..09f84a6c92b37 100644
--- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.production.min.js
+++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.production.min.js
@@ -1,17 +1,17 @@
-/**
- * @license React
- * react-dom-server.node.production.min.js
- *
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
+/*
+ React
+ react-dom-server.node.production.min.js
+
+ Copyright (c) Meta Platforms, Inc. and affiliates.
+
+ This source code is licensed under the MIT license found in the
+ LICENSE file in the root directory of this source tree.
+*/
'use strict';var ba=require("util"),ca=require("crypto"),ha=require("async_hooks"),ia=require("next/dist/compiled/react"),ja=require("react-dom");function oa(a){"function"===typeof a.flush&&a.flush()}var k=null,m=0,pa=!0;
function u(a,b){if("string"===typeof b){if(0!==b.length)if(2048<3*b.length)0]/;
-function B(a){if("boolean"===typeof a||"number"===typeof a)return""+a;a=""+a;var b=Ka.exec(a);if(b){var c="",d,e=0;for(d=b.index;d '),sb=y("