hadars 0.1.23 → 0.1.24

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.
@@ -0,0 +1,11 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined")
5
+ return require.apply(this, arguments);
6
+ throw new Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
9
+ export {
10
+ __require
11
+ };
package/dist/cli.js CHANGED
@@ -1,4 +1,11 @@
1
1
  #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined")
6
+ return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
2
9
 
3
10
  // cli.ts
4
11
  import { spawn as spawn2 } from "node:child_process";
@@ -160,6 +167,40 @@ function createElement(type, props, ...children) {
160
167
  }
161
168
 
162
169
  // src/slim-react/renderContext.ts
170
+ var CONTEXT_STORE_KEY = "__slimReactContextStore";
171
+ var _g = globalThis;
172
+ if (!_g[CONTEXT_STORE_KEY]) {
173
+ try {
174
+ const { AsyncLocalStorage } = __require("node:async_hooks");
175
+ _g[CONTEXT_STORE_KEY] = new AsyncLocalStorage();
176
+ } catch {
177
+ _g[CONTEXT_STORE_KEY] = null;
178
+ }
179
+ }
180
+ var _contextStore = _g[CONTEXT_STORE_KEY];
181
+ function runWithContextStore(fn) {
182
+ return _contextStore ? _contextStore.run(/* @__PURE__ */ new Map(), fn) : fn();
183
+ }
184
+ function getContextValue(context) {
185
+ const store = _contextStore?.getStore();
186
+ if (store && store.has(context))
187
+ return store.get(context);
188
+ const c = context;
189
+ return "_defaultValue" in c ? c._defaultValue : c._currentValue;
190
+ }
191
+ function pushContextValue(context, value) {
192
+ const store = _contextStore?.getStore();
193
+ const c = context;
194
+ const prev = store && store.has(context) ? store.get(context) : "_defaultValue" in c ? c._defaultValue : c._currentValue;
195
+ if (store)
196
+ store.set(context, value);
197
+ return prev;
198
+ }
199
+ function popContextValue(context, prev) {
200
+ const store = _contextStore?.getStore();
201
+ if (store)
202
+ store.set(context, prev);
203
+ }
163
204
  var GLOBAL_KEY = "__slimReactRenderState";
164
205
  var EMPTY = { id: 0, overflow: "", bits: 0 };
165
206
  function s() {
@@ -572,7 +613,7 @@ function renderComponent(type, props, writer, isSvg) {
572
613
  }
573
614
  if (typeOf === REACT_CONSUMER) {
574
615
  const ctx2 = type._context;
575
- const value = ctx2?._currentValue;
616
+ const value = ctx2 ? getContextValue(ctx2) : void 0;
576
617
  const result2 = typeof props.children === "function" ? props.children(value) : null;
577
618
  const savedScope2 = pushComponentScope();
578
619
  const finish2 = () => popComponentScope(savedScope2);
@@ -588,18 +629,20 @@ function renderComponent(type, props, writer, isSvg) {
588
629
  let ctx;
589
630
  if (isProvider) {
590
631
  ctx = type._context ?? type;
591
- prevCtxValue = ctx._currentValue;
592
- ctx._currentValue = props.value;
632
+ prevCtxValue = pushContextValue(ctx, props.value);
593
633
  }
594
634
  const savedScope = pushComponentScope();
595
635
  if (isProvider && typeof type !== "function") {
596
636
  const finish2 = () => {
597
637
  popComponentScope(savedScope);
598
- ctx._currentValue = prevCtxValue;
638
+ popContextValue(ctx, prevCtxValue);
599
639
  };
600
640
  const r2 = renderChildren(props.children, writer, isSvg);
601
641
  if (r2 && typeof r2.then === "function") {
602
- return r2.then(finish2);
642
+ return r2.then(finish2, (e) => {
643
+ finish2();
644
+ throw e;
645
+ });
603
646
  }
604
647
  finish2();
605
648
  return;
@@ -620,26 +663,35 @@ function renderComponent(type, props, writer, isSvg) {
620
663
  } catch (e) {
621
664
  popComponentScope(savedScope);
622
665
  if (isProvider)
623
- ctx._currentValue = prevCtxValue;
666
+ popContextValue(ctx, prevCtxValue);
624
667
  throw e;
625
668
  }
626
669
  const finish = () => {
627
670
  popComponentScope(savedScope);
628
671
  if (isProvider)
629
- ctx._currentValue = prevCtxValue;
672
+ popContextValue(ctx, prevCtxValue);
630
673
  };
631
674
  if (result instanceof Promise) {
632
675
  return result.then((resolved) => {
633
676
  const r2 = renderNode(resolved, writer, isSvg);
634
677
  if (r2 && typeof r2.then === "function") {
635
- return r2.then(finish);
678
+ return r2.then(finish, (e) => {
679
+ finish();
680
+ throw e;
681
+ });
636
682
  }
637
683
  finish();
684
+ }, (e) => {
685
+ finish();
686
+ throw e;
638
687
  });
639
688
  }
640
689
  const r = renderNode(result, writer, isSvg);
641
690
  if (r && typeof r.then === "function") {
642
- return r.then(finish);
691
+ return r.then(finish, (e) => {
692
+ finish();
693
+ throw e;
694
+ });
643
695
  }
644
696
  finish();
645
697
  }
@@ -723,35 +775,37 @@ async function renderSuspense(props, writer, isSvg = false) {
723
775
  }
724
776
  writer.write("<!--/$-->");
725
777
  }
726
- async function renderToString(element) {
727
- for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
728
- resetRenderState();
729
- const chunks = [];
730
- const writer = {
731
- lastWasText: false,
732
- write(c) {
733
- chunks.push(c);
734
- this.lastWasText = false;
735
- },
736
- text(s2) {
737
- chunks.push(s2);
738
- this.lastWasText = true;
739
- }
740
- };
741
- try {
742
- const r = renderNode(element, writer);
743
- if (r && typeof r.then === "function")
744
- await r;
745
- return chunks.join("");
746
- } catch (error) {
747
- if (error && typeof error.then === "function") {
748
- await error;
749
- continue;
778
+ function renderToString(element) {
779
+ return runWithContextStore(async () => {
780
+ for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
781
+ resetRenderState();
782
+ const chunks = [];
783
+ const writer = {
784
+ lastWasText: false,
785
+ write(c) {
786
+ chunks.push(c);
787
+ this.lastWasText = false;
788
+ },
789
+ text(s2) {
790
+ chunks.push(s2);
791
+ this.lastWasText = true;
792
+ }
793
+ };
794
+ try {
795
+ const r = renderNode(element, writer);
796
+ if (r && typeof r.then === "function")
797
+ await r;
798
+ return chunks.join("");
799
+ } catch (error) {
800
+ if (error && typeof error.then === "function") {
801
+ await error;
802
+ continue;
803
+ }
804
+ throw error;
750
805
  }
751
- throw error;
752
806
  }
753
- }
754
- throw new Error("[slim-react] renderToString exceeded maximum retries");
807
+ throw new Error("[slim-react] renderToString exceeded maximum retries");
808
+ });
755
809
  }
756
810
 
757
811
  // src/utils/response.tsx
@@ -1039,6 +1093,16 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
1039
1093
  "@emotion/styled": path.resolve(process.cwd(), "node_modules", "@emotion", "styled")
1040
1094
  } : void 0;
1041
1095
  const externals = isServerBuild ? [
1096
+ // Node.js built-ins — must not be bundled; resolved by the runtime.
1097
+ // Both the bare name and the node: prefix are listed because rspack
1098
+ // may encounter either form depending on how the import is written.
1099
+ "node:async_hooks",
1100
+ "async_hooks",
1101
+ "node:fs",
1102
+ "node:path",
1103
+ "node:os",
1104
+ "node:stream",
1105
+ "node:util",
1042
1106
  // react / react-dom are replaced by slim-react via alias above — not external.
1043
1107
  // emotion should be external on server builds to avoid client/browser code
1044
1108
  "@emotion/react",
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ import "./chunk-EZUCZHGV.js";
2
+
1
3
  // src/utils/Head.tsx
2
4
  import React from "react";
3
5
  import { jsx } from "react/jsx-runtime";
@@ -100,6 +100,40 @@ function createElement(type, props, ...children) {
100
100
  }
101
101
 
102
102
  // src/slim-react/renderContext.ts
103
+ var CONTEXT_STORE_KEY = "__slimReactContextStore";
104
+ var _g = globalThis;
105
+ if (!_g[CONTEXT_STORE_KEY]) {
106
+ try {
107
+ const { AsyncLocalStorage } = require("async_hooks");
108
+ _g[CONTEXT_STORE_KEY] = new AsyncLocalStorage();
109
+ } catch {
110
+ _g[CONTEXT_STORE_KEY] = null;
111
+ }
112
+ }
113
+ var _contextStore = _g[CONTEXT_STORE_KEY];
114
+ function runWithContextStore(fn) {
115
+ return _contextStore ? _contextStore.run(/* @__PURE__ */ new Map(), fn) : fn();
116
+ }
117
+ function getContextValue(context) {
118
+ const store = _contextStore?.getStore();
119
+ if (store && store.has(context))
120
+ return store.get(context);
121
+ const c = context;
122
+ return "_defaultValue" in c ? c._defaultValue : c._currentValue;
123
+ }
124
+ function pushContextValue(context, value) {
125
+ const store = _contextStore?.getStore();
126
+ const c = context;
127
+ const prev = store && store.has(context) ? store.get(context) : "_defaultValue" in c ? c._defaultValue : c._currentValue;
128
+ if (store)
129
+ store.set(context, value);
130
+ return prev;
131
+ }
132
+ function popContextValue(context, prev) {
133
+ const store = _contextStore?.getStore();
134
+ if (store)
135
+ store.set(context, prev);
136
+ }
103
137
  var GLOBAL_KEY = "__slimReactRenderState";
104
138
  var EMPTY = { id: 0, overflow: "", bits: 0 };
105
139
  function s() {
@@ -225,8 +259,8 @@ function useActionState(_action, initialState, _permalink) {
225
259
  }, false];
226
260
  }
227
261
  function use(usable) {
228
- if (typeof usable === "object" && usable !== null && "_currentValue" in usable) {
229
- return usable._currentValue;
262
+ if (typeof usable === "object" && usable !== null && ("_currentValue" in usable || "_defaultValue" in usable)) {
263
+ return getContextValue(usable);
230
264
  }
231
265
  const promise = usable;
232
266
  if (promise.status === "fulfilled")
@@ -242,6 +276,7 @@ function startTransition(callback) {
242
276
  // src/slim-react/context.ts
243
277
  function createContext(defaultValue) {
244
278
  const context = {
279
+ _defaultValue: defaultValue,
245
280
  _currentValue: defaultValue,
246
281
  Provider: null,
247
282
  Consumer: null
@@ -617,7 +652,7 @@ function renderComponent(type, props, writer, isSvg) {
617
652
  }
618
653
  if (typeOf === REACT_CONSUMER) {
619
654
  const ctx2 = type._context;
620
- const value = ctx2?._currentValue;
655
+ const value = ctx2 ? getContextValue(ctx2) : void 0;
621
656
  const result2 = typeof props.children === "function" ? props.children(value) : null;
622
657
  const savedScope2 = pushComponentScope();
623
658
  const finish2 = () => popComponentScope(savedScope2);
@@ -633,18 +668,20 @@ function renderComponent(type, props, writer, isSvg) {
633
668
  let ctx;
634
669
  if (isProvider) {
635
670
  ctx = type._context ?? type;
636
- prevCtxValue = ctx._currentValue;
637
- ctx._currentValue = props.value;
671
+ prevCtxValue = pushContextValue(ctx, props.value);
638
672
  }
639
673
  const savedScope = pushComponentScope();
640
674
  if (isProvider && typeof type !== "function") {
641
675
  const finish2 = () => {
642
676
  popComponentScope(savedScope);
643
- ctx._currentValue = prevCtxValue;
677
+ popContextValue(ctx, prevCtxValue);
644
678
  };
645
679
  const r2 = renderChildren(props.children, writer, isSvg);
646
680
  if (r2 && typeof r2.then === "function") {
647
- return r2.then(finish2);
681
+ return r2.then(finish2, (e) => {
682
+ finish2();
683
+ throw e;
684
+ });
648
685
  }
649
686
  finish2();
650
687
  return;
@@ -665,26 +702,35 @@ function renderComponent(type, props, writer, isSvg) {
665
702
  } catch (e) {
666
703
  popComponentScope(savedScope);
667
704
  if (isProvider)
668
- ctx._currentValue = prevCtxValue;
705
+ popContextValue(ctx, prevCtxValue);
669
706
  throw e;
670
707
  }
671
708
  const finish = () => {
672
709
  popComponentScope(savedScope);
673
710
  if (isProvider)
674
- ctx._currentValue = prevCtxValue;
711
+ popContextValue(ctx, prevCtxValue);
675
712
  };
676
713
  if (result instanceof Promise) {
677
714
  return result.then((resolved) => {
678
715
  const r2 = renderNode(resolved, writer, isSvg);
679
716
  if (r2 && typeof r2.then === "function") {
680
- return r2.then(finish);
717
+ return r2.then(finish, (e) => {
718
+ finish();
719
+ throw e;
720
+ });
681
721
  }
682
722
  finish();
723
+ }, (e) => {
724
+ finish();
725
+ throw e;
683
726
  });
684
727
  }
685
728
  const r = renderNode(result, writer, isSvg);
686
729
  if (r && typeof r.then === "function") {
687
- return r.then(finish);
730
+ return r.then(finish, (e) => {
731
+ finish();
732
+ throw e;
733
+ });
688
734
  }
689
735
  finish();
690
736
  }
@@ -770,7 +816,7 @@ async function renderSuspense(props, writer, isSvg = false) {
770
816
  }
771
817
  function renderToStream(element) {
772
818
  const encoder = new TextEncoder();
773
- return new ReadableStream({
819
+ return runWithContextStore(() => new ReadableStream({
774
820
  async start(controller) {
775
821
  resetRenderState();
776
822
  const writer = {
@@ -793,42 +839,44 @@ function renderToStream(element) {
793
839
  controller.error(error);
794
840
  }
795
841
  }
796
- });
842
+ }));
797
843
  }
798
- async function renderToString(element) {
799
- for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
800
- resetRenderState();
801
- const chunks = [];
802
- const writer = {
803
- lastWasText: false,
804
- write(c) {
805
- chunks.push(c);
806
- this.lastWasText = false;
807
- },
808
- text(s2) {
809
- chunks.push(s2);
810
- this.lastWasText = true;
811
- }
812
- };
813
- try {
814
- const r = renderNode(element, writer);
815
- if (r && typeof r.then === "function")
816
- await r;
817
- return chunks.join("");
818
- } catch (error) {
819
- if (error && typeof error.then === "function") {
820
- await error;
821
- continue;
844
+ function renderToString(element) {
845
+ return runWithContextStore(async () => {
846
+ for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
847
+ resetRenderState();
848
+ const chunks = [];
849
+ const writer = {
850
+ lastWasText: false,
851
+ write(c) {
852
+ chunks.push(c);
853
+ this.lastWasText = false;
854
+ },
855
+ text(s2) {
856
+ chunks.push(s2);
857
+ this.lastWasText = true;
858
+ }
859
+ };
860
+ try {
861
+ const r = renderNode(element, writer);
862
+ if (r && typeof r.then === "function")
863
+ await r;
864
+ return chunks.join("");
865
+ } catch (error) {
866
+ if (error && typeof error.then === "function") {
867
+ await error;
868
+ continue;
869
+ }
870
+ throw error;
822
871
  }
823
- throw error;
824
872
  }
825
- }
826
- throw new Error("[slim-react] renderToString exceeded maximum retries");
873
+ throw new Error("[slim-react] renderToString exceeded maximum retries");
874
+ });
827
875
  }
828
876
 
829
877
  // src/slim-react/index.ts
830
878
  function useContext(context) {
831
- return context._currentValue;
879
+ return getContextValue(context);
832
880
  }
833
881
  var Suspense = SUSPENSE_TYPE;
834
882
  function isValidElement(obj) {
@@ -49,6 +49,7 @@ declare function startTransition(callback: () => void): void;
49
49
  * save / restore around Provider renders (handled by the renderer).
50
50
  */
51
51
  interface Context<T> {
52
+ _defaultValue: T;
52
53
  _currentValue: T;
53
54
  Provider: ContextProvider<T>;
54
55
  Consumer: (props: {
@@ -7,8 +7,45 @@ import {
7
7
  createElement,
8
8
  jsx
9
9
  } from "../chunk-OS3V4CPN.js";
10
+ import {
11
+ __require
12
+ } from "../chunk-EZUCZHGV.js";
10
13
 
11
14
  // src/slim-react/renderContext.ts
15
+ var CONTEXT_STORE_KEY = "__slimReactContextStore";
16
+ var _g = globalThis;
17
+ if (!_g[CONTEXT_STORE_KEY]) {
18
+ try {
19
+ const { AsyncLocalStorage } = __require("node:async_hooks");
20
+ _g[CONTEXT_STORE_KEY] = new AsyncLocalStorage();
21
+ } catch {
22
+ _g[CONTEXT_STORE_KEY] = null;
23
+ }
24
+ }
25
+ var _contextStore = _g[CONTEXT_STORE_KEY];
26
+ function runWithContextStore(fn) {
27
+ return _contextStore ? _contextStore.run(/* @__PURE__ */ new Map(), fn) : fn();
28
+ }
29
+ function getContextValue(context) {
30
+ const store = _contextStore?.getStore();
31
+ if (store && store.has(context))
32
+ return store.get(context);
33
+ const c = context;
34
+ return "_defaultValue" in c ? c._defaultValue : c._currentValue;
35
+ }
36
+ function pushContextValue(context, value) {
37
+ const store = _contextStore?.getStore();
38
+ const c = context;
39
+ const prev = store && store.has(context) ? store.get(context) : "_defaultValue" in c ? c._defaultValue : c._currentValue;
40
+ if (store)
41
+ store.set(context, value);
42
+ return prev;
43
+ }
44
+ function popContextValue(context, prev) {
45
+ const store = _contextStore?.getStore();
46
+ if (store)
47
+ store.set(context, prev);
48
+ }
12
49
  var GLOBAL_KEY = "__slimReactRenderState";
13
50
  var EMPTY = { id: 0, overflow: "", bits: 0 };
14
51
  function s() {
@@ -134,8 +171,8 @@ function useActionState(_action, initialState, _permalink) {
134
171
  }, false];
135
172
  }
136
173
  function use(usable) {
137
- if (typeof usable === "object" && usable !== null && "_currentValue" in usable) {
138
- return usable._currentValue;
174
+ if (typeof usable === "object" && usable !== null && ("_currentValue" in usable || "_defaultValue" in usable)) {
175
+ return getContextValue(usable);
139
176
  }
140
177
  const promise = usable;
141
178
  if (promise.status === "fulfilled")
@@ -151,6 +188,7 @@ function startTransition(callback) {
151
188
  // src/slim-react/context.ts
152
189
  function createContext(defaultValue) {
153
190
  const context = {
191
+ _defaultValue: defaultValue,
154
192
  _currentValue: defaultValue,
155
193
  Provider: null,
156
194
  Consumer: null
@@ -526,7 +564,7 @@ function renderComponent(type, props, writer, isSvg) {
526
564
  }
527
565
  if (typeOf === REACT_CONSUMER) {
528
566
  const ctx2 = type._context;
529
- const value = ctx2?._currentValue;
567
+ const value = ctx2 ? getContextValue(ctx2) : void 0;
530
568
  const result2 = typeof props.children === "function" ? props.children(value) : null;
531
569
  const savedScope2 = pushComponentScope();
532
570
  const finish2 = () => popComponentScope(savedScope2);
@@ -542,18 +580,20 @@ function renderComponent(type, props, writer, isSvg) {
542
580
  let ctx;
543
581
  if (isProvider) {
544
582
  ctx = type._context ?? type;
545
- prevCtxValue = ctx._currentValue;
546
- ctx._currentValue = props.value;
583
+ prevCtxValue = pushContextValue(ctx, props.value);
547
584
  }
548
585
  const savedScope = pushComponentScope();
549
586
  if (isProvider && typeof type !== "function") {
550
587
  const finish2 = () => {
551
588
  popComponentScope(savedScope);
552
- ctx._currentValue = prevCtxValue;
589
+ popContextValue(ctx, prevCtxValue);
553
590
  };
554
591
  const r2 = renderChildren(props.children, writer, isSvg);
555
592
  if (r2 && typeof r2.then === "function") {
556
- return r2.then(finish2);
593
+ return r2.then(finish2, (e) => {
594
+ finish2();
595
+ throw e;
596
+ });
557
597
  }
558
598
  finish2();
559
599
  return;
@@ -574,26 +614,35 @@ function renderComponent(type, props, writer, isSvg) {
574
614
  } catch (e) {
575
615
  popComponentScope(savedScope);
576
616
  if (isProvider)
577
- ctx._currentValue = prevCtxValue;
617
+ popContextValue(ctx, prevCtxValue);
578
618
  throw e;
579
619
  }
580
620
  const finish = () => {
581
621
  popComponentScope(savedScope);
582
622
  if (isProvider)
583
- ctx._currentValue = prevCtxValue;
623
+ popContextValue(ctx, prevCtxValue);
584
624
  };
585
625
  if (result instanceof Promise) {
586
626
  return result.then((resolved) => {
587
627
  const r2 = renderNode(resolved, writer, isSvg);
588
628
  if (r2 && typeof r2.then === "function") {
589
- return r2.then(finish);
629
+ return r2.then(finish, (e) => {
630
+ finish();
631
+ throw e;
632
+ });
590
633
  }
591
634
  finish();
635
+ }, (e) => {
636
+ finish();
637
+ throw e;
592
638
  });
593
639
  }
594
640
  const r = renderNode(result, writer, isSvg);
595
641
  if (r && typeof r.then === "function") {
596
- return r.then(finish);
642
+ return r.then(finish, (e) => {
643
+ finish();
644
+ throw e;
645
+ });
597
646
  }
598
647
  finish();
599
648
  }
@@ -679,7 +728,7 @@ async function renderSuspense(props, writer, isSvg = false) {
679
728
  }
680
729
  function renderToStream(element) {
681
730
  const encoder = new TextEncoder();
682
- return new ReadableStream({
731
+ return runWithContextStore(() => new ReadableStream({
683
732
  async start(controller) {
684
733
  resetRenderState();
685
734
  const writer = {
@@ -702,42 +751,44 @@ function renderToStream(element) {
702
751
  controller.error(error);
703
752
  }
704
753
  }
705
- });
754
+ }));
706
755
  }
707
- async function renderToString(element) {
708
- for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
709
- resetRenderState();
710
- const chunks = [];
711
- const writer = {
712
- lastWasText: false,
713
- write(c) {
714
- chunks.push(c);
715
- this.lastWasText = false;
716
- },
717
- text(s2) {
718
- chunks.push(s2);
719
- this.lastWasText = true;
720
- }
721
- };
722
- try {
723
- const r = renderNode(element, writer);
724
- if (r && typeof r.then === "function")
725
- await r;
726
- return chunks.join("");
727
- } catch (error) {
728
- if (error && typeof error.then === "function") {
729
- await error;
730
- continue;
756
+ function renderToString(element) {
757
+ return runWithContextStore(async () => {
758
+ for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
759
+ resetRenderState();
760
+ const chunks = [];
761
+ const writer = {
762
+ lastWasText: false,
763
+ write(c) {
764
+ chunks.push(c);
765
+ this.lastWasText = false;
766
+ },
767
+ text(s2) {
768
+ chunks.push(s2);
769
+ this.lastWasText = true;
770
+ }
771
+ };
772
+ try {
773
+ const r = renderNode(element, writer);
774
+ if (r && typeof r.then === "function")
775
+ await r;
776
+ return chunks.join("");
777
+ } catch (error) {
778
+ if (error && typeof error.then === "function") {
779
+ await error;
780
+ continue;
781
+ }
782
+ throw error;
731
783
  }
732
- throw error;
733
784
  }
734
- }
735
- throw new Error("[slim-react] renderToString exceeded maximum retries");
785
+ throw new Error("[slim-react] renderToString exceeded maximum retries");
786
+ });
736
787
  }
737
788
 
738
789
  // src/slim-react/index.ts
739
790
  function useContext(context) {
740
- return context._currentValue;
791
+ return getContextValue(context);
741
792
  }
742
793
  var Suspense = SUSPENSE_TYPE;
743
794
  function isValidElement(obj) {
@@ -2,6 +2,7 @@ import {
2
2
  Fragment,
3
3
  jsx
4
4
  } from "../chunk-OS3V4CPN.js";
5
+ import "../chunk-EZUCZHGV.js";
5
6
  export {
6
7
  Fragment,
7
8
  jsx,
@@ -1,3 +1,11 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined")
5
+ return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
1
9
  // src/ssr-render-worker.ts
2
10
  import { workerData, parentPort } from "node:worker_threads";
3
11
  import { pathToFileURL } from "node:url";
@@ -67,6 +75,40 @@ function createElement(type, props, ...children) {
67
75
  }
68
76
 
69
77
  // src/slim-react/renderContext.ts
78
+ var CONTEXT_STORE_KEY = "__slimReactContextStore";
79
+ var _g = globalThis;
80
+ if (!_g[CONTEXT_STORE_KEY]) {
81
+ try {
82
+ const { AsyncLocalStorage } = __require("node:async_hooks");
83
+ _g[CONTEXT_STORE_KEY] = new AsyncLocalStorage();
84
+ } catch {
85
+ _g[CONTEXT_STORE_KEY] = null;
86
+ }
87
+ }
88
+ var _contextStore = _g[CONTEXT_STORE_KEY];
89
+ function runWithContextStore(fn) {
90
+ return _contextStore ? _contextStore.run(/* @__PURE__ */ new Map(), fn) : fn();
91
+ }
92
+ function getContextValue(context) {
93
+ const store = _contextStore?.getStore();
94
+ if (store && store.has(context))
95
+ return store.get(context);
96
+ const c = context;
97
+ return "_defaultValue" in c ? c._defaultValue : c._currentValue;
98
+ }
99
+ function pushContextValue(context, value) {
100
+ const store = _contextStore?.getStore();
101
+ const c = context;
102
+ const prev = store && store.has(context) ? store.get(context) : "_defaultValue" in c ? c._defaultValue : c._currentValue;
103
+ if (store)
104
+ store.set(context, value);
105
+ return prev;
106
+ }
107
+ function popContextValue(context, prev) {
108
+ const store = _contextStore?.getStore();
109
+ if (store)
110
+ store.set(context, prev);
111
+ }
70
112
  var GLOBAL_KEY = "__slimReactRenderState";
71
113
  var EMPTY = { id: 0, overflow: "", bits: 0 };
72
114
  function s() {
@@ -479,7 +521,7 @@ function renderComponent(type, props, writer, isSvg) {
479
521
  }
480
522
  if (typeOf === REACT_CONSUMER) {
481
523
  const ctx2 = type._context;
482
- const value = ctx2?._currentValue;
524
+ const value = ctx2 ? getContextValue(ctx2) : void 0;
483
525
  const result2 = typeof props.children === "function" ? props.children(value) : null;
484
526
  const savedScope2 = pushComponentScope();
485
527
  const finish2 = () => popComponentScope(savedScope2);
@@ -495,18 +537,20 @@ function renderComponent(type, props, writer, isSvg) {
495
537
  let ctx;
496
538
  if (isProvider) {
497
539
  ctx = type._context ?? type;
498
- prevCtxValue = ctx._currentValue;
499
- ctx._currentValue = props.value;
540
+ prevCtxValue = pushContextValue(ctx, props.value);
500
541
  }
501
542
  const savedScope = pushComponentScope();
502
543
  if (isProvider && typeof type !== "function") {
503
544
  const finish2 = () => {
504
545
  popComponentScope(savedScope);
505
- ctx._currentValue = prevCtxValue;
546
+ popContextValue(ctx, prevCtxValue);
506
547
  };
507
548
  const r2 = renderChildren(props.children, writer, isSvg);
508
549
  if (r2 && typeof r2.then === "function") {
509
- return r2.then(finish2);
550
+ return r2.then(finish2, (e) => {
551
+ finish2();
552
+ throw e;
553
+ });
510
554
  }
511
555
  finish2();
512
556
  return;
@@ -527,26 +571,35 @@ function renderComponent(type, props, writer, isSvg) {
527
571
  } catch (e) {
528
572
  popComponentScope(savedScope);
529
573
  if (isProvider)
530
- ctx._currentValue = prevCtxValue;
574
+ popContextValue(ctx, prevCtxValue);
531
575
  throw e;
532
576
  }
533
577
  const finish = () => {
534
578
  popComponentScope(savedScope);
535
579
  if (isProvider)
536
- ctx._currentValue = prevCtxValue;
580
+ popContextValue(ctx, prevCtxValue);
537
581
  };
538
582
  if (result instanceof Promise) {
539
583
  return result.then((resolved) => {
540
584
  const r2 = renderNode(resolved, writer, isSvg);
541
585
  if (r2 && typeof r2.then === "function") {
542
- return r2.then(finish);
586
+ return r2.then(finish, (e) => {
587
+ finish();
588
+ throw e;
589
+ });
543
590
  }
544
591
  finish();
592
+ }, (e) => {
593
+ finish();
594
+ throw e;
545
595
  });
546
596
  }
547
597
  const r = renderNode(result, writer, isSvg);
548
598
  if (r && typeof r.then === "function") {
549
- return r.then(finish);
599
+ return r.then(finish, (e) => {
600
+ finish();
601
+ throw e;
602
+ });
550
603
  }
551
604
  finish();
552
605
  }
@@ -630,35 +683,37 @@ async function renderSuspense(props, writer, isSvg = false) {
630
683
  }
631
684
  writer.write("<!--/$-->");
632
685
  }
633
- async function renderToString(element) {
634
- for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
635
- resetRenderState();
636
- const chunks = [];
637
- const writer = {
638
- lastWasText: false,
639
- write(c) {
640
- chunks.push(c);
641
- this.lastWasText = false;
642
- },
643
- text(s2) {
644
- chunks.push(s2);
645
- this.lastWasText = true;
646
- }
647
- };
648
- try {
649
- const r = renderNode(element, writer);
650
- if (r && typeof r.then === "function")
651
- await r;
652
- return chunks.join("");
653
- } catch (error) {
654
- if (error && typeof error.then === "function") {
655
- await error;
656
- continue;
686
+ function renderToString(element) {
687
+ return runWithContextStore(async () => {
688
+ for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
689
+ resetRenderState();
690
+ const chunks = [];
691
+ const writer = {
692
+ lastWasText: false,
693
+ write(c) {
694
+ chunks.push(c);
695
+ this.lastWasText = false;
696
+ },
697
+ text(s2) {
698
+ chunks.push(s2);
699
+ this.lastWasText = true;
700
+ }
701
+ };
702
+ try {
703
+ const r = renderNode(element, writer);
704
+ if (r && typeof r.then === "function")
705
+ await r;
706
+ return chunks.join("");
707
+ } catch (error) {
708
+ if (error && typeof error.then === "function") {
709
+ await error;
710
+ continue;
711
+ }
712
+ throw error;
657
713
  }
658
- throw error;
659
714
  }
660
- }
661
- throw new Error("[slim-react] renderToString exceeded maximum retries");
715
+ throw new Error("[slim-react] renderToString exceeded maximum retries");
716
+ });
662
717
  }
663
718
 
664
719
  // src/ssr-render-worker.ts
package/dist/ssr-watch.js CHANGED
@@ -179,6 +179,16 @@ var buildCompilerConfig = (entry2, opts, includeHotPlugin) => {
179
179
  "@emotion/styled": path.resolve(process.cwd(), "node_modules", "@emotion", "styled")
180
180
  } : void 0;
181
181
  const externals = isServerBuild ? [
182
+ // Node.js built-ins — must not be bundled; resolved by the runtime.
183
+ // Both the bare name and the node: prefix are listed because rspack
184
+ // may encounter either form depending on how the import is written.
185
+ "node:async_hooks",
186
+ "async_hooks",
187
+ "node:fs",
188
+ "node:path",
189
+ "node:os",
190
+ "node:stream",
191
+ "node:util",
182
192
  // react / react-dom are replaced by slim-react via alias above — not external.
183
193
  // emotion should be external on server builds to avoid client/browser code
184
194
  "@emotion/react",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hadars",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "Minimal SSR framework for React — rspack, HMR, TypeScript, Bun/Node/Deno",
5
5
  "module": "./dist/index.js",
6
6
  "type": "module",
@@ -9,7 +9,8 @@ import type { SlimNode } from "./types";
9
9
  */
10
10
 
11
11
  export interface Context<T> {
12
- _currentValue: T;
12
+ _defaultValue: T;
13
+ _currentValue: T; // kept for external compat (real React contexts passed to useContext)
13
14
  Provider: ContextProvider<T>;
14
15
  Consumer: (props: { children: (value: T) => SlimNode }) => SlimNode;
15
16
  }
@@ -23,6 +24,7 @@ export type ContextProvider<T> = ((props: {
23
24
 
24
25
  export function createContext<T>(defaultValue: T): Context<T> {
25
26
  const context: Context<T> = {
27
+ _defaultValue: defaultValue,
26
28
  _currentValue: defaultValue,
27
29
  Provider: null!,
28
30
  Consumer: null!,
@@ -6,7 +6,7 @@
6
6
  * compatible libraries to work during server-side rendering.
7
7
  */
8
8
 
9
- import { makeId } from "./renderContext";
9
+ import { makeId, getContextValue } from "./renderContext";
10
10
 
11
11
  // ---- useState ----
12
12
  export function useState<T>(
@@ -115,9 +115,9 @@ export function use<T>(
115
115
  if (
116
116
  typeof usable === "object" &&
117
117
  usable !== null &&
118
- "_currentValue" in usable
118
+ ("_currentValue" in usable || "_defaultValue" in usable)
119
119
  ) {
120
- return (usable as { _currentValue: T })._currentValue;
120
+ return getContextValue<T>(usable as object);
121
121
  }
122
122
 
123
123
  // Promise – Suspense protocol
@@ -67,12 +67,10 @@ export {
67
67
  import { createContext } from "./context";
68
68
  export { createContext, type Context } from "./context";
69
69
 
70
- // Re-export useContext from hooks.ts? No – we have it in context.ts
71
- // Actually useContext reads from the context object, let's export a
72
- // single implementation that lives close to createContext:
70
+ import { getContextValue } from "./renderContext";
73
71
  import type { Context } from "./context";
74
72
  export function useContext<T>(context: Context<T>): T {
75
- return context._currentValue;
73
+ return getContextValue<T>(context);
76
74
  }
77
75
 
78
76
  // ---- Rendering ----
@@ -30,6 +30,10 @@ import {
30
30
  popComponentScope,
31
31
  snapshotContext,
32
32
  restoreContext,
33
+ pushContextValue,
34
+ popContextValue,
35
+ getContextValue,
36
+ runWithContextStore,
33
37
  } from "./renderContext";
34
38
 
35
39
  // ---------------------------------------------------------------------------
@@ -566,7 +570,7 @@ function renderComponent(
566
570
  // React.Consumer (React 19) — call the children render prop with the current value
567
571
  if (typeOf === REACT_CONSUMER) {
568
572
  const ctx = (type as any)._context;
569
- const value = ctx?._currentValue;
573
+ const value = ctx ? getContextValue(ctx) : undefined;
570
574
  const result: SlimNode =
571
575
  typeof props.children === "function" ? props.children(value) : null;
572
576
  const savedScope = pushComponentScope();
@@ -594,8 +598,7 @@ function renderComponent(
594
598
  if (isProvider) {
595
599
  // Resolve the actual context object from any provider variant
596
600
  ctx = (type as any)._context ?? type;
597
- prevCtxValue = ctx._currentValue;
598
- ctx._currentValue = props.value;
601
+ prevCtxValue = pushContextValue(ctx, props.value);
599
602
  }
600
603
 
601
604
  // Each component gets a fresh local-ID counter (for multiple useId calls).
@@ -606,11 +609,11 @@ function renderComponent(
606
609
  if (isProvider && typeof type !== "function") {
607
610
  const finish = () => {
608
611
  popComponentScope(savedScope);
609
- ctx._currentValue = prevCtxValue;
612
+ popContextValue(ctx, prevCtxValue);
610
613
  };
611
614
  const r = renderChildren(props.children, writer, isSvg);
612
615
  if (r && typeof (r as any).then === "function") {
613
- return (r as Promise<void>).then(finish);
616
+ return (r as Promise<void>).then(finish, (e) => { finish(); throw e; });
614
617
  }
615
618
  finish();
616
619
  return;
@@ -631,13 +634,13 @@ function renderComponent(
631
634
  }
632
635
  } catch (e) {
633
636
  popComponentScope(savedScope);
634
- if (isProvider) ctx._currentValue = prevCtxValue;
637
+ if (isProvider) popContextValue(ctx, prevCtxValue);
635
638
  throw e;
636
639
  }
637
640
 
638
641
  const finish = () => {
639
642
  popComponentScope(savedScope);
640
- if (isProvider) ctx._currentValue = prevCtxValue;
643
+ if (isProvider) popContextValue(ctx, prevCtxValue);
641
644
  };
642
645
 
643
646
  // Async component
@@ -645,16 +648,16 @@ function renderComponent(
645
648
  return result.then((resolved) => {
646
649
  const r = renderNode(resolved, writer, isSvg);
647
650
  if (r && typeof (r as any).then === "function") {
648
- return (r as Promise<void>).then(finish);
651
+ return (r as Promise<void>).then(finish, (e) => { finish(); throw e; });
649
652
  }
650
653
  finish();
651
- });
654
+ }, (e) => { finish(); throw e; });
652
655
  }
653
656
 
654
657
  const r = renderNode(result, writer, isSvg);
655
658
 
656
659
  if (r && typeof (r as any).then === "function") {
657
- return (r as Promise<void>).then(finish);
660
+ return (r as Promise<void>).then(finish, (e) => { finish(); throw e; });
658
661
  }
659
662
  finish();
660
663
  }
@@ -803,7 +806,7 @@ async function renderSuspense(
803
806
  export function renderToStream(element: SlimNode): ReadableStream<Uint8Array> {
804
807
  const encoder = new TextEncoder();
805
808
 
806
- return new ReadableStream({
809
+ return runWithContextStore(() => new ReadableStream({
807
810
  async start(controller) {
808
811
  resetRenderState();
809
812
 
@@ -827,7 +830,7 @@ export function renderToStream(element: SlimNode): ReadableStream<Uint8Array> {
827
830
  controller.error(error);
828
831
  }
829
832
  },
830
- });
833
+ }));
831
834
  }
832
835
 
833
836
  /**
@@ -835,28 +838,30 @@ export function renderToStream(element: SlimNode): ReadableStream<Uint8Array> {
835
838
  * Retries the full tree when a component throws a Promise (Suspense protocol),
836
839
  * so useServerData and similar hooks work without requiring explicit <Suspense>.
837
840
  */
838
- export async function renderToString(element: SlimNode): Promise<string> {
839
- for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
840
- resetRenderState();
841
- const chunks: string[] = [];
842
- const writer: Writer = {
843
- lastWasText: false,
844
- write(c) { chunks.push(c); this.lastWasText = false; },
845
- text(s) { chunks.push(s); this.lastWasText = true; },
846
- };
847
- try {
848
- const r = renderNode(element, writer);
849
- if (r && typeof (r as any).then === "function") await r;
850
- return chunks.join("");
851
- } catch (error) {
852
- if (error && typeof (error as any).then === "function") {
853
- await (error as Promise<unknown>);
854
- continue;
841
+ export function renderToString(element: SlimNode): Promise<string> {
842
+ return runWithContextStore(async () => {
843
+ for (let attempt = 0; attempt < MAX_SUSPENSE_RETRIES; attempt++) {
844
+ resetRenderState();
845
+ const chunks: string[] = [];
846
+ const writer: Writer = {
847
+ lastWasText: false,
848
+ write(c) { chunks.push(c); this.lastWasText = false; },
849
+ text(s) { chunks.push(s); this.lastWasText = true; },
850
+ };
851
+ try {
852
+ const r = renderNode(element, writer);
853
+ if (r && typeof (r as any).then === "function") await r;
854
+ return chunks.join("");
855
+ } catch (error) {
856
+ if (error && typeof (error as any).then === "function") {
857
+ await (error as Promise<unknown>);
858
+ continue;
859
+ }
860
+ throw error;
855
861
  }
856
- throw error;
857
862
  }
858
- }
859
- throw new Error("[slim-react] renderToString exceeded maximum retries");
863
+ throw new Error("[slim-react] renderToString exceeded maximum retries");
864
+ });
860
865
  }
861
866
 
862
867
  /** Alias matching React 18+ server API naming. */
@@ -1,12 +1,71 @@
1
1
  /**
2
- * Render-time context for tree-position-based `useId`.
2
+ * Render-time context for tree-position-based `useId` and React Context values.
3
3
  *
4
4
  * State lives on `globalThis` rather than module-level variables so that
5
5
  * multiple slim-react instances (the render worker's direct import and the
6
- * SSR bundle's bundled copy) share the same context without any coordination.
7
- * Safe because each worker processes one render at a time; `resetRenderState`
8
- * is always called at the top of every `renderToString` / `renderToStream`.
6
+ * SSR bundle's bundled copy) share the same singletons without coordination.
7
+ *
8
+ * Context values are stored in an AsyncLocalStorage<Map> so each concurrent
9
+ * SSR request gets its own isolated scope that propagates through all awaits.
10
+ * Call `runWithContextStore` at the start of every render to establish the scope.
11
+ */
12
+
13
+ // Shared AsyncLocalStorage instance — kept on globalThis so both copies of
14
+ // slim-react (direct import + SSR bundle) use the same store.
15
+ // The import is done with require() inside a try/catch so that bundlers that
16
+ // cannot resolve node:async_hooks (e.g. rspack without target:node set) do
17
+ // not fail at build time — the SSR render process always runs in Node.js and
18
+ // will find the module at runtime regardless.
19
+ const CONTEXT_STORE_KEY = "__slimReactContextStore";
20
+ const _g = globalThis as any;
21
+ if (!_g[CONTEXT_STORE_KEY]) {
22
+ try {
23
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
24
+ const { AsyncLocalStorage } = require("node:async_hooks") as typeof import("node:async_hooks");
25
+ _g[CONTEXT_STORE_KEY] = new AsyncLocalStorage<Map<object, unknown>>();
26
+ } catch {
27
+ // Fallback: no-op store — context values fall back to _defaultValue.
28
+ // This should never happen in a real SSR environment.
29
+ _g[CONTEXT_STORE_KEY] = null;
30
+ }
31
+ }
32
+ const _contextStore: { run<T>(store: Map<object,unknown>, fn: () => T): T; getStore(): Map<object,unknown> | undefined } | null = _g[CONTEXT_STORE_KEY];
33
+
34
+ /** Wrap a render entry-point so it gets its own isolated context-value scope. */
35
+ export function runWithContextStore<T>(fn: () => T): T {
36
+ return _contextStore ? _contextStore.run(new Map(), fn) : fn();
37
+ }
38
+
39
+ /**
40
+ * Read the current value for a context within the active render.
41
+ * Falls back to `_defaultValue` (or `_currentValue` for external contexts).
42
+ */
43
+ export function getContextValue<T>(context: object): T {
44
+ const store = _contextStore?.getStore();
45
+ if (store && store.has(context)) return store.get(context) as T;
46
+ const c = context as any;
47
+ return ("_defaultValue" in c ? c._defaultValue : c._currentValue) as T;
48
+ }
49
+
50
+ /**
51
+ * Push a new value for a context Provider onto the per-request store.
52
+ * Returns the previous value so the caller can restore it later.
9
53
  */
54
+ export function pushContextValue(context: object, value: unknown): unknown {
55
+ const store = _contextStore?.getStore();
56
+ const c = context as any;
57
+ const prev = store && store.has(context)
58
+ ? store.get(context)
59
+ : ("_defaultValue" in c ? c._defaultValue : c._currentValue);
60
+ if (store) store.set(context, value);
61
+ return prev;
62
+ }
63
+
64
+ /** Restore a previously saved context value (called by Provider on exit). */
65
+ export function popContextValue(context: object, prev: unknown): void {
66
+ const store = _contextStore?.getStore();
67
+ if (store) store.set(context, prev);
68
+ }
10
69
 
11
70
  export interface TreeContext {
12
71
  id: number;
@@ -226,6 +226,11 @@ const buildCompilerConfig = (
226
226
  } : undefined;
227
227
 
228
228
  const externals = isServerBuild ? [
229
+ // Node.js built-ins — must not be bundled; resolved by the runtime.
230
+ // Both the bare name and the node: prefix are listed because rspack
231
+ // may encounter either form depending on how the import is written.
232
+ 'node:async_hooks', 'async_hooks',
233
+ 'node:fs', 'node:path', 'node:os', 'node:stream', 'node:util',
229
234
  // react / react-dom are replaced by slim-react via alias above — not external.
230
235
  // emotion should be external on server builds to avoid client/browser code
231
236
  '@emotion/react',