@vmz/core 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dom-ssr.js +7 -2
- package/dist/server.js +19 -6
- package/package.json +1 -1
package/dist/dom-ssr.js
CHANGED
|
@@ -425,8 +425,8 @@ function* streamSerializeChunks(node) {
|
|
|
425
425
|
}
|
|
426
426
|
}
|
|
427
427
|
/**
|
|
428
|
-
* Document-free rowKernel SSR
|
|
429
|
-
* Prefer
|
|
428
|
+
* Document-free rowKernel SSR fill (transitional / pre-0.1.7 emit only).
|
|
429
|
+
* Prefer `serializeItem` (IR schedule). Do not treat this as the long-term contract.
|
|
430
430
|
* @param {{ html: string, textSlots?: Record<string, number>, hostFields?: string[] }} rk
|
|
431
431
|
* @param {any} item
|
|
432
432
|
* @param {any} key
|
|
@@ -731,7 +731,12 @@ const serializeApi = {
|
|
|
731
731
|
if (typeof spec.createItem === 'function') {
|
|
732
732
|
dom = spec.createItem.call(inst, serializeApi, box);
|
|
733
733
|
}
|
|
734
|
+
else if (typeof spec.serializeItem === 'function') {
|
|
735
|
+
// IR-homologous schedule (v0.1.7): same Direct body as fat createItem.
|
|
736
|
+
dom = spec.serializeItem.call(inst, serializeApi, box);
|
|
737
|
+
}
|
|
734
738
|
else if (spec.rowKernel && typeof spec.rowKernel.html === 'string') {
|
|
739
|
+
// Transitional only: pre-0.1.7 emit without serializeItem.
|
|
735
740
|
dom = serializeRowFromKernel(inst, spec.rowKernel, box, k);
|
|
736
741
|
}
|
|
737
742
|
if (dom) {
|
package/dist/server.js
CHANGED
|
@@ -690,12 +690,15 @@ function sendHtml(res, status, html) {
|
|
|
690
690
|
* @param {AbortSignal} [signal]
|
|
691
691
|
*/
|
|
692
692
|
async function sendHtmlStream(res, status, source, signal) {
|
|
693
|
-
res.
|
|
693
|
+
const aborted = () => Boolean(signal?.aborted || res.destroyed || res.writableEnded || !res.writable);
|
|
694
|
+
const headers = {
|
|
694
695
|
'content-type': 'text/html; charset=utf-8',
|
|
695
696
|
'transfer-encoding': 'chunked',
|
|
696
697
|
'cache-control': 'no-cache',
|
|
697
|
-
}
|
|
698
|
-
|
|
698
|
+
};
|
|
699
|
+
// Defer writeHead until the first successful chunk so SSR throw → clean 500
|
|
700
|
+
// (not headersSent + destroy → ERR_EMPTY_RESPONSE).
|
|
701
|
+
let started = false;
|
|
699
702
|
try {
|
|
700
703
|
for await (const chunk of source) {
|
|
701
704
|
if (aborted())
|
|
@@ -703,6 +706,10 @@ async function sendHtmlStream(res, status, source, signal) {
|
|
|
703
706
|
if (chunk == null || chunk === '')
|
|
704
707
|
continue;
|
|
705
708
|
const s = typeof chunk === 'string' ? chunk : String(chunk);
|
|
709
|
+
if (!started) {
|
|
710
|
+
res.writeHead(status, headers);
|
|
711
|
+
started = true;
|
|
712
|
+
}
|
|
706
713
|
const ok = res.write(s);
|
|
707
714
|
if (!ok) {
|
|
708
715
|
await Promise.race([
|
|
@@ -720,12 +727,18 @@ async function sendHtmlStream(res, status, source, signal) {
|
|
|
720
727
|
break;
|
|
721
728
|
}
|
|
722
729
|
}
|
|
730
|
+
if (!started && !aborted()) {
|
|
731
|
+
res.writeHead(status, headers);
|
|
732
|
+
started = true;
|
|
733
|
+
}
|
|
723
734
|
}
|
|
724
735
|
catch (err) {
|
|
725
|
-
if (
|
|
726
|
-
|
|
736
|
+
if (aborted())
|
|
737
|
+
return;
|
|
738
|
+
// Before headers: let outer handler sendJson(500). After headers: rethrow → destroy.
|
|
739
|
+
throw err;
|
|
727
740
|
}
|
|
728
|
-
if (!res.writableEnded && !res.destroyed) {
|
|
741
|
+
if (started && !res.writableEnded && !res.destroyed) {
|
|
729
742
|
res.end();
|
|
730
743
|
}
|
|
731
744
|
}
|