@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 CHANGED
@@ -425,8 +425,8 @@ function* streamSerializeChunks(node) {
425
425
  }
426
426
  }
427
427
  /**
428
- * Document-free rowKernel SSR: fill generator text placeholders (` `) from textSlots + item.
429
- * Prefer this over linkedom createItem was omitted because html + slots are enough.
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.writeHead(status, {
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
- const aborted = () => Boolean(signal?.aborted || res.destroyed || res.writableEnded || !res.writable);
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 (!aborted())
726
- throw err;
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vmz/core",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "description": "VMZ production runtime core — DOM / SSR / HTTP / WriteBarrier (no compiler)",
6
6
  "exports": {