hadars 0.1.16 → 0.1.18

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.
@@ -1,140 +1,639 @@
1
1
  // src/ssr-render-worker.ts
2
2
  import { workerData, parentPort } from "node:worker_threads";
3
- import { createRequire } from "node:module";
4
- import pathMod from "node:path";
5
3
  import { pathToFileURL } from "node:url";
4
+
5
+ // src/utils/segmentCache.ts
6
+ function getStore() {
7
+ const g = globalThis;
8
+ if (!g.__hadarsSegmentStore) {
9
+ g.__hadarsSegmentStore = /* @__PURE__ */ new Map();
10
+ }
11
+ return g.__hadarsSegmentStore;
12
+ }
13
+ function setSegment(key, html, ttl) {
14
+ getStore().set(key, {
15
+ html,
16
+ expiresAt: ttl != null ? Date.now() + ttl : null
17
+ });
18
+ }
19
+ function processSegmentCache(html) {
20
+ let prev;
21
+ do {
22
+ prev = html;
23
+ html = html.replace(
24
+ /<hadars-c([^>]*)>([\s\S]*?)<\/hadars-c>/g,
25
+ (match, attrs, content) => {
26
+ const cacheM = /data-cache="([^"]+)"/.exec(attrs);
27
+ const keyM = /data-key="([^"]+)"/.exec(attrs);
28
+ const ttlM = /data-ttl="(\d+)"/.exec(attrs);
29
+ if (!cacheM || !keyM)
30
+ return match;
31
+ if (cacheM[1] === "miss") {
32
+ setSegment(keyM[1], content, ttlM ? Number(ttlM[1]) : void 0);
33
+ return content;
34
+ }
35
+ if (cacheM[1] === "hit")
36
+ return content;
37
+ return match;
38
+ }
39
+ );
40
+ } while (html !== prev);
41
+ return html;
42
+ }
43
+
44
+ // src/slim-react/types.ts
45
+ var SLIM_ELEMENT = Symbol.for("react.element");
46
+ var FRAGMENT_TYPE = Symbol.for("react.fragment");
47
+ var SUSPENSE_TYPE = Symbol.for("react.suspense");
48
+
49
+ // src/slim-react/jsx.ts
50
+ var Fragment = FRAGMENT_TYPE;
51
+ function createElement(type, props, ...children) {
52
+ const normalizedProps = { ...props || {} };
53
+ if (children.length === 1) {
54
+ normalizedProps.children = children[0];
55
+ } else if (children.length > 1) {
56
+ normalizedProps.children = children;
57
+ }
58
+ const key = normalizedProps.key ?? null;
59
+ delete normalizedProps.key;
60
+ return {
61
+ $$typeof: SLIM_ELEMENT,
62
+ type,
63
+ props: normalizedProps,
64
+ key
65
+ };
66
+ }
67
+
68
+ // src/slim-react/renderContext.ts
69
+ var GLOBAL_KEY = "__slimReactRenderState";
70
+ var EMPTY = { id: 0, overflow: "", bits: 0 };
71
+ function s() {
72
+ const g = globalThis;
73
+ if (!g[GLOBAL_KEY]) {
74
+ g[GLOBAL_KEY] = { currentTreeContext: { ...EMPTY }, localIdCounter: 0, idPrefix: "" };
75
+ }
76
+ return g[GLOBAL_KEY];
77
+ }
78
+ function resetRenderState() {
79
+ const st = s();
80
+ st.currentTreeContext = { ...EMPTY };
81
+ st.localIdCounter = 0;
82
+ }
83
+ function pushTreeContext(totalChildren, index) {
84
+ const st = s();
85
+ const saved = { ...st.currentTreeContext };
86
+ const pendingBits = 32 - Math.clz32(totalChildren);
87
+ const slot = index + 1;
88
+ const totalBits = st.currentTreeContext.bits + pendingBits;
89
+ if (totalBits <= 30) {
90
+ st.currentTreeContext = {
91
+ id: st.currentTreeContext.id << pendingBits | slot,
92
+ overflow: st.currentTreeContext.overflow,
93
+ bits: totalBits
94
+ };
95
+ } else {
96
+ let newOverflow = st.currentTreeContext.overflow;
97
+ if (st.currentTreeContext.bits > 0)
98
+ newOverflow += st.currentTreeContext.id.toString(32);
99
+ st.currentTreeContext = { id: 1 << pendingBits | slot, overflow: newOverflow, bits: pendingBits };
100
+ }
101
+ return saved;
102
+ }
103
+ function popTreeContext(saved) {
104
+ s().currentTreeContext = saved;
105
+ }
106
+ function pushComponentScope() {
107
+ const st = s();
108
+ const saved = st.localIdCounter;
109
+ st.localIdCounter = 0;
110
+ return saved;
111
+ }
112
+ function popComponentScope(saved) {
113
+ s().localIdCounter = saved;
114
+ }
115
+ function snapshotContext() {
116
+ const st = s();
117
+ return { tree: { ...st.currentTreeContext }, localId: st.localIdCounter };
118
+ }
119
+ function restoreContext(snap) {
120
+ const st = s();
121
+ st.currentTreeContext = { ...snap.tree };
122
+ st.localIdCounter = snap.localId;
123
+ }
124
+
125
+ // src/slim-react/render.ts
126
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
127
+ "area",
128
+ "base",
129
+ "br",
130
+ "col",
131
+ "embed",
132
+ "hr",
133
+ "img",
134
+ "input",
135
+ "link",
136
+ "meta",
137
+ "param",
138
+ "source",
139
+ "track",
140
+ "wbr"
141
+ ]);
142
+ function escapeHtml(str) {
143
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
144
+ }
145
+ function escapeAttr(str) {
146
+ return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
147
+ }
148
+ function styleObjectToString(style) {
149
+ return Object.entries(style).map(([key, value]) => {
150
+ const cssKey = key.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
151
+ return `${cssKey}:${value}`;
152
+ }).join(";");
153
+ }
154
+ var SVG_ATTR_MAP = {
155
+ // Presentation / geometry
156
+ accentHeight: "accent-height",
157
+ alignmentBaseline: "alignment-baseline",
158
+ arabicForm: "arabic-form",
159
+ baselineShift: "baseline-shift",
160
+ capHeight: "cap-height",
161
+ clipPath: "clip-path",
162
+ clipRule: "clip-rule",
163
+ colorInterpolation: "color-interpolation",
164
+ colorInterpolationFilters: "color-interpolation-filters",
165
+ colorProfile: "color-profile",
166
+ dominantBaseline: "dominant-baseline",
167
+ enableBackground: "enable-background",
168
+ fillOpacity: "fill-opacity",
169
+ fillRule: "fill-rule",
170
+ floodColor: "flood-color",
171
+ floodOpacity: "flood-opacity",
172
+ fontFamily: "font-family",
173
+ fontSize: "font-size",
174
+ fontSizeAdjust: "font-size-adjust",
175
+ fontStretch: "font-stretch",
176
+ fontStyle: "font-style",
177
+ fontVariant: "font-variant",
178
+ fontWeight: "font-weight",
179
+ glyphName: "glyph-name",
180
+ glyphOrientationHorizontal: "glyph-orientation-horizontal",
181
+ glyphOrientationVertical: "glyph-orientation-vertical",
182
+ horizAdvX: "horiz-adv-x",
183
+ horizOriginX: "horiz-origin-x",
184
+ imageRendering: "image-rendering",
185
+ letterSpacing: "letter-spacing",
186
+ lightingColor: "lighting-color",
187
+ markerEnd: "marker-end",
188
+ markerMid: "marker-mid",
189
+ markerStart: "marker-start",
190
+ overlinePosition: "overline-position",
191
+ overlineThickness: "overline-thickness",
192
+ paintOrder: "paint-order",
193
+ panose1: "panose-1",
194
+ pointerEvents: "pointer-events",
195
+ renderingIntent: "rendering-intent",
196
+ shapeRendering: "shape-rendering",
197
+ stopColor: "stop-color",
198
+ stopOpacity: "stop-opacity",
199
+ strikethroughPosition: "strikethrough-position",
200
+ strikethroughThickness: "strikethrough-thickness",
201
+ strokeDasharray: "stroke-dasharray",
202
+ strokeDashoffset: "stroke-dashoffset",
203
+ strokeLinecap: "stroke-linecap",
204
+ strokeLinejoin: "stroke-linejoin",
205
+ strokeMiterlimit: "stroke-miterlimit",
206
+ strokeOpacity: "stroke-opacity",
207
+ strokeWidth: "stroke-width",
208
+ textAnchor: "text-anchor",
209
+ textDecoration: "text-decoration",
210
+ textRendering: "text-rendering",
211
+ underlinePosition: "underline-position",
212
+ underlineThickness: "underline-thickness",
213
+ unicodeBidi: "unicode-bidi",
214
+ unicodeRange: "unicode-range",
215
+ unitsPerEm: "units-per-em",
216
+ vAlphabetic: "v-alphabetic",
217
+ vHanging: "v-hanging",
218
+ vIdeographic: "v-ideographic",
219
+ vMathematical: "v-mathematical",
220
+ vertAdvY: "vert-adv-y",
221
+ vertOriginX: "vert-origin-x",
222
+ vertOriginY: "vert-origin-y",
223
+ wordSpacing: "word-spacing",
224
+ writingMode: "writing-mode",
225
+ xHeight: "x-height",
226
+ // Namespace-prefixed
227
+ xlinkActuate: "xlink:actuate",
228
+ xlinkArcrole: "xlink:arcrole",
229
+ xlinkHref: "xlink:href",
230
+ xlinkRole: "xlink:role",
231
+ xlinkShow: "xlink:show",
232
+ xlinkTitle: "xlink:title",
233
+ xlinkType: "xlink:type",
234
+ xmlBase: "xml:base",
235
+ xmlLang: "xml:lang",
236
+ xmlSpace: "xml:space",
237
+ xmlns: "xmlns",
238
+ xmlnsXlink: "xmlns:xlink",
239
+ // Filter / lighting
240
+ baseFrequency: "baseFrequency",
241
+ colorInterpolation_filters: "color-interpolation-filters",
242
+ diffuseConstant: "diffuseConstant",
243
+ edgeMode: "edgeMode",
244
+ filterUnits: "filterUnits",
245
+ gradientTransform: "gradientTransform",
246
+ gradientUnits: "gradientUnits",
247
+ kernelMatrix: "kernelMatrix",
248
+ kernelUnitLength: "kernelUnitLength",
249
+ lengthAdjust: "lengthAdjust",
250
+ limitingConeAngle: "limitingConeAngle",
251
+ markerHeight: "markerHeight",
252
+ markerWidth: "markerWidth",
253
+ maskContentUnits: "maskContentUnits",
254
+ maskUnits: "maskUnits",
255
+ numOctaves: "numOctaves",
256
+ pathLength: "pathLength",
257
+ patternContentUnits: "patternContentUnits",
258
+ patternTransform: "patternTransform",
259
+ patternUnits: "patternUnits",
260
+ pointsAtX: "pointsAtX",
261
+ pointsAtY: "pointsAtY",
262
+ pointsAtZ: "pointsAtZ",
263
+ preserveAspectRatio: "preserveAspectRatio",
264
+ primitiveUnits: "primitiveUnits",
265
+ refX: "refX",
266
+ refY: "refY",
267
+ repeatCount: "repeatCount",
268
+ repeatDur: "repeatDur",
269
+ specularConstant: "specularConstant",
270
+ specularExponent: "specularExponent",
271
+ spreadMethod: "spreadMethod",
272
+ startOffset: "startOffset",
273
+ stdDeviation: "stdDeviation",
274
+ stitchTiles: "stitchTiles",
275
+ surfaceScale: "surfaceScale",
276
+ systemLanguage: "systemLanguage",
277
+ tableValues: "tableValues",
278
+ targetX: "targetX",
279
+ targetY: "targetY",
280
+ textLength: "textLength",
281
+ viewBox: "viewBox",
282
+ xChannelSelector: "xChannelSelector",
283
+ yChannelSelector: "yChannelSelector"
284
+ };
285
+ function renderAttributes(props, isSvg) {
286
+ let attrs = "";
287
+ for (const [key, value] of Object.entries(props)) {
288
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML")
289
+ continue;
290
+ if (key.startsWith("on") && key.length > 2 && key[2] === key[2].toUpperCase())
291
+ continue;
292
+ let attrName;
293
+ if (isSvg && key in SVG_ATTR_MAP) {
294
+ attrName = SVG_ATTR_MAP[key];
295
+ } else {
296
+ attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key === "tabIndex" ? "tabindex" : key;
297
+ }
298
+ if (value === false || value == null)
299
+ continue;
300
+ if (value === true) {
301
+ attrs += ` ${attrName}`;
302
+ continue;
303
+ }
304
+ if (key === "style" && typeof value === "object") {
305
+ attrs += ` style="${escapeAttr(styleObjectToString(value))}"`;
306
+ continue;
307
+ }
308
+ attrs += ` ${attrName}="${escapeAttr(String(value))}"`;
309
+ }
310
+ return attrs;
311
+ }
312
+ var BufferWriter = class {
313
+ chunks = [];
314
+ write(chunk) {
315
+ this.chunks.push(chunk);
316
+ }
317
+ flush(target) {
318
+ for (const c of this.chunks)
319
+ target.write(c);
320
+ }
321
+ };
322
+ function renderNode(node, writer, isSvg = false) {
323
+ if (node == null || typeof node === "boolean")
324
+ return;
325
+ if (typeof node === "string") {
326
+ writer.write(escapeHtml(node));
327
+ return;
328
+ }
329
+ if (typeof node === "number") {
330
+ writer.write(String(node));
331
+ return;
332
+ }
333
+ if (Array.isArray(node)) {
334
+ return renderChildArray(node, writer, isSvg);
335
+ }
336
+ if (typeof node === "object" && node !== null && Symbol.iterator in node && !("$$typeof" in node)) {
337
+ return renderChildArray(
338
+ Array.from(node),
339
+ writer,
340
+ isSvg
341
+ );
342
+ }
343
+ if (typeof node === "object" && node !== null && "$$typeof" in node && node.$$typeof === SLIM_ELEMENT) {
344
+ const element = node;
345
+ const { type, props } = element;
346
+ if (type === FRAGMENT_TYPE) {
347
+ return renderChildren(props.children, writer, isSvg);
348
+ }
349
+ if (type === SUSPENSE_TYPE) {
350
+ return renderSuspense(props, writer, isSvg);
351
+ }
352
+ if (typeof type === "function") {
353
+ return renderComponent(type, props, writer, isSvg);
354
+ }
355
+ if (typeof type === "string") {
356
+ return renderHostElement(type, props, writer, isSvg);
357
+ }
358
+ }
359
+ }
360
+ function renderHostElement(tag, props, writer, isSvg) {
361
+ const enteringSvg = tag === "svg";
362
+ const childSvg = isSvg || enteringSvg;
363
+ const effectiveProps = enteringSvg && !props.xmlns ? { xmlns: "http://www.w3.org/2000/svg", ...props } : props;
364
+ writer.write(`<${tag}${renderAttributes(effectiveProps, childSvg)}>`);
365
+ const childContext = tag === "foreignObject" ? false : childSvg;
366
+ let inner = void 0;
367
+ if (props.dangerouslySetInnerHTML) {
368
+ writer.write(props.dangerouslySetInnerHTML.__html);
369
+ } else {
370
+ inner = renderChildren(props.children, writer, childContext);
371
+ }
372
+ if (inner && typeof inner.then === "function") {
373
+ return inner.then(() => {
374
+ if (!VOID_ELEMENTS.has(tag))
375
+ writer.write(`</${tag}>`);
376
+ });
377
+ }
378
+ if (!VOID_ELEMENTS.has(tag))
379
+ writer.write(`</${tag}>`);
380
+ }
381
+ var REACT_MEMO = Symbol.for("react.memo");
382
+ var REACT_FORWARD_REF = Symbol.for("react.forward_ref");
383
+ var REACT_PROVIDER = Symbol.for("react.provider");
384
+ var REACT_CONTEXT = Symbol.for("react.context");
385
+ function renderComponent(type, props, writer, isSvg) {
386
+ const typeOf = type?.$$typeof;
387
+ if (typeOf === REACT_MEMO) {
388
+ return renderNode(
389
+ { $$typeof: SLIM_ELEMENT, type: type.type, props, key: null },
390
+ writer,
391
+ isSvg
392
+ );
393
+ }
394
+ if (typeOf === REACT_FORWARD_REF) {
395
+ return renderComponent(type.render, props, writer, isSvg);
396
+ }
397
+ const isProvider = "_context" in type || typeOf === REACT_PROVIDER || typeOf === REACT_CONTEXT && "value" in props;
398
+ let prevCtxValue;
399
+ let ctx;
400
+ if (isProvider) {
401
+ ctx = type._context ?? type;
402
+ prevCtxValue = ctx._currentValue;
403
+ ctx._currentValue = props.value;
404
+ }
405
+ const savedScope = pushComponentScope();
406
+ let result;
407
+ try {
408
+ if (type.prototype && typeof type.prototype.render === "function") {
409
+ const instance = new type(props);
410
+ result = instance.render();
411
+ } else {
412
+ result = type(props);
413
+ }
414
+ } catch (e) {
415
+ popComponentScope(savedScope);
416
+ if (isProvider)
417
+ ctx._currentValue = prevCtxValue;
418
+ throw e;
419
+ }
420
+ const finish = () => {
421
+ popComponentScope(savedScope);
422
+ if (isProvider)
423
+ ctx._currentValue = prevCtxValue;
424
+ };
425
+ if (result instanceof Promise) {
426
+ return result.then((resolved) => {
427
+ const r2 = renderNode(resolved, writer, isSvg);
428
+ if (r2 && typeof r2.then === "function") {
429
+ return r2.then(finish);
430
+ }
431
+ finish();
432
+ });
433
+ }
434
+ const r = renderNode(result, writer, isSvg);
435
+ if (r && typeof r.then === "function") {
436
+ return r.then(finish);
437
+ }
438
+ finish();
439
+ }
440
+ function isTextLike(node) {
441
+ return typeof node === "string" || typeof node === "number";
442
+ }
443
+ function renderChildArray(children, writer, isSvg) {
444
+ const totalChildren = children.length;
445
+ for (let i = 0; i < totalChildren; i++) {
446
+ if (i > 0 && isTextLike(children[i]) && isTextLike(children[i - 1])) {
447
+ writer.write("<!-- -->");
448
+ }
449
+ const savedTree = pushTreeContext(totalChildren, i);
450
+ const r = renderNode(children[i], writer, isSvg);
451
+ if (r && typeof r.then === "function") {
452
+ return r.then(() => {
453
+ popTreeContext(savedTree);
454
+ return renderChildArrayFrom(children, i + 1, writer, isSvg);
455
+ });
456
+ }
457
+ popTreeContext(savedTree);
458
+ }
459
+ }
460
+ function renderChildArrayFrom(children, startIndex, writer, isSvg) {
461
+ const totalChildren = children.length;
462
+ for (let i = startIndex; i < totalChildren; i++) {
463
+ if (i > 0 && isTextLike(children[i]) && isTextLike(children[i - 1])) {
464
+ writer.write("<!-- -->");
465
+ }
466
+ const savedTree = pushTreeContext(totalChildren, i);
467
+ const r = renderNode(children[i], writer, isSvg);
468
+ if (r && typeof r.then === "function") {
469
+ return r.then(() => {
470
+ popTreeContext(savedTree);
471
+ return renderChildArrayFrom(children, i + 1, writer, isSvg);
472
+ });
473
+ }
474
+ popTreeContext(savedTree);
475
+ }
476
+ }
477
+ function renderChildren(children, writer, isSvg = false) {
478
+ if (children == null)
479
+ return;
480
+ if (Array.isArray(children)) {
481
+ return renderChildArray(children, writer, isSvg);
482
+ }
483
+ return renderNode(children, writer, isSvg);
484
+ }
485
+ var MAX_SUSPENSE_RETRIES = 25;
486
+ async function renderSuspense(props, writer, isSvg = false) {
487
+ const { children, fallback } = props;
488
+ let attempts = 0;
489
+ const snap = snapshotContext();
490
+ while (attempts < MAX_SUSPENSE_RETRIES) {
491
+ restoreContext(snap);
492
+ try {
493
+ const buffer = new BufferWriter();
494
+ const r = renderNode(children, buffer, isSvg);
495
+ if (r && typeof r.then === "function") {
496
+ await r;
497
+ }
498
+ writer.write("<!--$-->");
499
+ buffer.flush(writer);
500
+ writer.write("<!--/$-->");
501
+ return;
502
+ } catch (error) {
503
+ if (error && typeof error.then === "function") {
504
+ await error;
505
+ attempts++;
506
+ } else {
507
+ throw error;
508
+ }
509
+ }
510
+ }
511
+ restoreContext(snap);
512
+ writer.write("<!--$?-->");
513
+ if (fallback) {
514
+ const r = renderNode(fallback, writer, isSvg);
515
+ if (r && typeof r.then === "function")
516
+ await r;
517
+ }
518
+ writer.write("<!--/$-->");
519
+ }
520
+ async function renderToString(element) {
521
+ for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
522
+ resetRenderState();
523
+ const chunks = [];
524
+ const writer = { write(c) {
525
+ chunks.push(c);
526
+ } };
527
+ try {
528
+ const r = renderNode(element, writer);
529
+ if (r && typeof r.then === "function")
530
+ await r;
531
+ return chunks.join("");
532
+ } catch (error) {
533
+ if (error && typeof error.then === "function") {
534
+ await error;
535
+ continue;
536
+ }
537
+ throw error;
538
+ }
539
+ }
540
+ throw new Error("[slim-react] renderToString exceeded maximum retries");
541
+ }
542
+
543
+ // src/ssr-render-worker.ts
6
544
  var { ssrBundlePath } = workerData;
7
- var _React = null;
8
- var _renderToStaticMarkup = null;
9
- var _renderToString = null;
10
545
  var _ssrMod = null;
11
546
  async function init() {
12
- if (_React && _ssrMod)
547
+ if (_ssrMod)
13
548
  return;
14
- const req = createRequire(pathMod.resolve(process.cwd(), "__hadars_fake__.js"));
15
- if (!_React) {
16
- const reactPath = pathToFileURL(req.resolve("react")).href;
17
- const reactMod = await import(reactPath);
18
- _React = reactMod.default ?? reactMod;
19
- }
20
- if (!_renderToString || !_renderToStaticMarkup) {
21
- const serverPath = pathToFileURL(req.resolve("react-dom/server")).href;
22
- const serverMod = await import(serverPath);
23
- _renderToString = serverMod.renderToString;
24
- _renderToStaticMarkup = serverMod.renderToStaticMarkup;
25
- }
26
- if (!_ssrMod) {
27
- _ssrMod = await import(pathToFileURL(ssrBundlePath).href);
28
- }
29
- }
30
- function deserializeRequest(s) {
31
- const init2 = { method: s.method, headers: new Headers(s.headers) };
32
- if (s.body)
33
- init2.body = s.body.buffer;
34
- const req = new Request(s.url, init2);
35
- Object.assign(req, {
36
- pathname: s.pathname,
37
- search: s.search,
38
- location: s.location,
39
- cookies: s.cookies
40
- });
549
+ _ssrMod = await import(pathToFileURL(ssrBundlePath).href);
550
+ }
551
+ function deserializeRequest(s2) {
552
+ const init2 = { method: s2.method, headers: new Headers(s2.headers) };
553
+ if (s2.body)
554
+ init2.body = s2.body.buffer;
555
+ const req = new Request(s2.url, init2);
556
+ Object.assign(req, { pathname: s2.pathname, search: s2.search, location: s2.location, cookies: s2.cookies });
41
557
  return req;
42
558
  }
559
+ var ESC = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" };
560
+ var escAttr = (s2) => s2.replace(/[&<>"]/g, (c) => ESC[c] ?? c);
561
+ var escText = (s2) => s2.replace(/[&<>]/g, (c) => ESC[c] ?? c);
562
+ var HEAD_ATTR = {
563
+ className: "class",
564
+ htmlFor: "for",
565
+ httpEquiv: "http-equiv",
566
+ charSet: "charset",
567
+ crossOrigin: "crossorigin"
568
+ };
569
+ function renderHeadTag(tag, id, opts, selfClose = false) {
570
+ let a = ` id="${escAttr(id)}"`;
571
+ let inner = "";
572
+ for (const [k, v] of Object.entries(opts)) {
573
+ if (k === "key" || k === "children")
574
+ continue;
575
+ if (k === "dangerouslySetInnerHTML") {
576
+ inner = v.__html ?? "";
577
+ continue;
578
+ }
579
+ const attr = HEAD_ATTR[k] ?? k;
580
+ if (v === true)
581
+ a += ` ${attr}`;
582
+ else if (v !== false && v != null)
583
+ a += ` ${attr}="${escAttr(String(v))}"`;
584
+ }
585
+ return selfClose ? `<${tag}${a}>` : `<${tag}${a}>${inner}</${tag}>`;
586
+ }
43
587
  function buildHeadHtml(head) {
44
- const R = _React;
45
- const metaEntries = Object.entries(head.meta ?? {});
46
- const linkEntries = Object.entries(head.link ?? {});
47
- const styleEntries = Object.entries(head.style ?? {});
48
- const scriptEntries = Object.entries(head.script ?? {});
49
- return _renderToStaticMarkup(
50
- R.createElement(
51
- R.Fragment,
52
- null,
53
- R.createElement("title", null, head.title),
54
- ...metaEntries.map(([id, opts]) => R.createElement("meta", { key: id, id, ...opts })),
55
- ...linkEntries.map(([id, opts]) => R.createElement("link", { key: id, id, ...opts })),
56
- ...styleEntries.map(([id, opts]) => R.createElement("style", { key: id, id, ...opts })),
57
- ...scriptEntries.map(([id, opts]) => R.createElement("script", { key: id, id, ...opts }))
58
- )
59
- );
60
- }
61
- function buildReactPage(appProps, clientProps) {
62
- const R = _React;
63
- const Component = _ssrMod.default;
64
- return R.createElement(
65
- R.Fragment,
66
- null,
67
- R.createElement(
68
- "div",
69
- { id: "app" },
70
- R.createElement(Component, appProps)
71
- ),
72
- R.createElement("script", {
73
- id: "hadars",
74
- type: "application/json",
75
- dangerouslySetInnerHTML: {
76
- __html: JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, "\\u003c")
77
- }
78
- })
79
- );
588
+ let html = `<title>${escText(head.title ?? "")}</title>`;
589
+ for (const [id, opts] of Object.entries(head.meta ?? {}))
590
+ html += renderHeadTag("meta", id, opts, true);
591
+ for (const [id, opts] of Object.entries(head.link ?? {}))
592
+ html += renderHeadTag("link", id, opts, true);
593
+ for (const [id, opts] of Object.entries(head.style ?? {}))
594
+ html += renderHeadTag("style", id, opts);
595
+ for (const [id, opts] of Object.entries(head.script ?? {}))
596
+ html += renderHeadTag("script", id, opts);
597
+ return html;
80
598
  }
81
599
  async function runFullLifecycle(serialReq) {
82
- const R = _React;
83
600
  const Component = _ssrMod.default;
84
601
  const { getInitProps, getAfterRenderProps, getFinalProps } = _ssrMod;
85
602
  const parsedReq = deserializeRequest(serialReq);
86
- const unsuspend = { cache: /* @__PURE__ */ new Map(), hasPending: false };
87
603
  const context = {
88
- head: { title: "Hadars App", meta: {}, link: {}, style: {}, script: {}, status: 200 },
89
- _unsuspend: unsuspend
604
+ head: { title: "Hadars App", meta: {}, link: {}, style: {}, script: {}, status: 200 }
90
605
  };
91
606
  let props = {
92
607
  ...getInitProps ? await getInitProps(parsedReq) : {},
93
608
  location: serialReq.location,
94
609
  context
95
610
  };
96
- let html = "";
97
- let iters = 0;
98
- do {
99
- unsuspend.hasPending = false;
100
- try {
101
- globalThis.__hadarsUnsuspend = unsuspend;
102
- html = _renderToStaticMarkup(R.createElement(Component, props));
103
- } finally {
104
- globalThis.__hadarsUnsuspend = null;
105
- }
106
- if (unsuspend.hasPending) {
107
- const pending = [...unsuspend.cache.values()].filter((e) => e.status === "pending").map((e) => e.promise);
108
- await Promise.all(pending);
109
- }
110
- } while (unsuspend.hasPending && ++iters < 25);
111
- if (unsuspend.hasPending) {
112
- console.warn("[hadars] SSR render loop hit the 25-iteration cap \u2014 some useServerData values may not be resolved. Check for data dependencies that are never fulfilled.");
113
- }
114
- props = getAfterRenderProps ? await getAfterRenderProps(props, html) : props;
611
+ const unsuspend = { cache: /* @__PURE__ */ new Map() };
612
+ globalThis.__hadarsUnsuspend = unsuspend;
115
613
  try {
116
- globalThis.__hadarsUnsuspend = unsuspend;
117
- _renderToStaticMarkup(R.createElement(Component, { ...props, location: serialReq.location, context }));
614
+ let html = await renderToString(createElement(Component, props));
615
+ if (getAfterRenderProps) {
616
+ props = await getAfterRenderProps(props, html);
617
+ await renderToString(
618
+ createElement(Component, { ...props, location: serialReq.location, context })
619
+ );
620
+ }
118
621
  } finally {
119
622
  globalThis.__hadarsUnsuspend = null;
120
623
  }
624
+ const { context: _ctx, ...restProps } = getFinalProps ? await getFinalProps(props) : props;
121
625
  const serverData = {};
122
- for (const [k, v] of unsuspend.cache) {
123
- if (v.status === "fulfilled")
124
- serverData[k] = v.value;
125
- if (v.status === "suspense-cached")
126
- serverData[k] = v.value;
626
+ for (const [key, entry] of unsuspend.cache) {
627
+ if (entry.status === "fulfilled")
628
+ serverData[key] = entry.value;
127
629
  }
128
- const { context: _ctx, ...restProps } = getFinalProps ? await getFinalProps(props) : props;
129
630
  const clientProps = {
130
631
  ...restProps,
131
632
  location: serialReq.location,
132
633
  ...Object.keys(serverData).length > 0 ? { __serverData: serverData } : {}
133
634
  };
134
- const headHtml = buildHeadHtml(context.head);
135
- const status = context.head.status ?? 200;
136
635
  const finalAppProps = { ...props, location: serialReq.location, context };
137
- return { finalAppProps, clientProps, headHtml, status, unsuspend };
636
+ return { finalAppProps, clientProps, unsuspend, headHtml: buildHeadHtml(context.head), status: context.head.status ?? 200 };
138
637
  }
139
638
  parentPort.on("message", async (msg) => {
140
639
  const { id, type, request } = msg;
@@ -142,18 +641,30 @@ parentPort.on("message", async (msg) => {
142
641
  await init();
143
642
  if (type !== "renderFull")
144
643
  return;
145
- const { finalAppProps, clientProps, headHtml, status, unsuspend } = await runFullLifecycle(request);
146
- const ReactPage = buildReactPage(finalAppProps, clientProps);
644
+ const { finalAppProps, clientProps, unsuspend, headHtml, status } = await runFullLifecycle(request);
645
+ const Component = _ssrMod.default;
646
+ const page = createElement(
647
+ Fragment,
648
+ null,
649
+ createElement("div", { id: "app" }, createElement(Component, finalAppProps)),
650
+ createElement("script", {
651
+ id: "hadars",
652
+ type: "application/json",
653
+ dangerouslySetInnerHTML: {
654
+ __html: JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, "\\u003c")
655
+ }
656
+ })
657
+ );
658
+ globalThis.__hadarsUnsuspend = unsuspend;
147
659
  let html;
148
660
  try {
149
- globalThis.__hadarsUnsuspend = unsuspend;
150
- html = _renderToString(ReactPage);
661
+ html = await renderToString(page);
151
662
  } finally {
152
663
  globalThis.__hadarsUnsuspend = null;
153
664
  }
665
+ html = processSegmentCache(html);
154
666
  parentPort.postMessage({ id, html, headHtml, status });
155
667
  } catch (err) {
156
- globalThis.__hadarsUnsuspend = null;
157
668
  parentPort.postMessage({ id, error: err?.message ?? String(err) });
158
669
  }
159
670
  });