@logixjs/react 0.1.0 → 1.0.0

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.
Files changed (36) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +1 -1
  3. package/dist/Hooks.cjs +462 -325
  4. package/dist/Hooks.d.cts +6 -6
  5. package/dist/Hooks.d.ts +6 -6
  6. package/dist/Hooks.js +3 -3
  7. package/dist/{ModuleRef-wZSQ3Wwo.d.cts → ModuleRef-gZmL6Zvb.d.cts} +8 -3
  8. package/dist/{ModuleRef-wZSQ3Wwo.d.ts → ModuleRef-gZmL6Zvb.d.ts} +8 -3
  9. package/dist/ModuleScope.cjs +596 -362
  10. package/dist/ModuleScope.d.cts +4 -4
  11. package/dist/ModuleScope.d.ts +4 -4
  12. package/dist/ModuleScope.js +4 -4
  13. package/dist/Platform.cjs +1 -4
  14. package/dist/Platform.d.cts +1 -2
  15. package/dist/Platform.d.ts +1 -2
  16. package/dist/Platform.js +1 -1
  17. package/dist/ReactPlatform.cjs +543 -309
  18. package/dist/ReactPlatform.d.cts +2 -2
  19. package/dist/ReactPlatform.d.ts +2 -2
  20. package/dist/ReactPlatform.js +5 -5
  21. package/dist/RuntimeProvider.cjs +276 -56
  22. package/dist/RuntimeProvider.js +2 -2
  23. package/dist/{chunk-PYWHL7TA.js → chunk-6NLXTHZ7.js} +8 -8
  24. package/dist/{chunk-UFFCJGSZ.js → chunk-E3ZXST5F.js} +256 -240
  25. package/dist/{chunk-4G7H66OY.js → chunk-KYWW4KMQ.js} +3 -3
  26. package/dist/{chunk-2WFULYPJ.js → chunk-L7KTYBXN.js} +155 -32
  27. package/dist/{chunk-ZANGOPUQ.js → chunk-NKYV44OG.js} +1 -4
  28. package/dist/{chunk-G5MRIFKK.js → chunk-SDQF3WRT.js} +7 -7
  29. package/dist/{chunk-JXAJTWSZ.js → chunk-XSGDBJXD.js} +122 -25
  30. package/dist/index.cjs +564 -333
  31. package/dist/index.d.cts +2 -2
  32. package/dist/index.d.ts +2 -2
  33. package/dist/index.js +7 -7
  34. package/dist/{useDispatch-BnzYVkRE.d.ts → useDispatch-CiDimIYZ.d.ts} +13 -15
  35. package/dist/{useDispatch-CnO5-66H.d.cts → useDispatch-DiwQQAfC.d.cts} +13 -15
  36. package/package.json +12 -4
package/dist/Hooks.cjs CHANGED
@@ -125,14 +125,11 @@ var useLayerBinding = (runtime, layer, enabled, onError) => {
125
125
  const newScope = import_effect.Effect.runSync(import_effect.Scope.make());
126
126
  const buildEffect = import_effect.Effect.gen(function* () {
127
127
  const context = yield* import_effect.Layer.buildWithScope(layer, newScope);
128
- const applyEnv = (effect) => import_effect.Effect.mapInputContext(
129
- import_effect.Scope.extend(effect, newScope),
130
- (parent) => import_effect.Context.merge(parent, context)
131
- );
132
- const loggers = yield* applyEnv(import_effect.FiberRef.get(import_effect.FiberRef.currentLoggers));
133
- const logLevel = yield* applyEnv(import_effect.FiberRef.get(import_effect.FiberRef.currentLogLevel));
128
+ const applyEnv = (effect) => import_effect.Scope.provide(newScope)(import_effect.Effect.provideServices(effect, context));
129
+ const loggers = yield* applyEnv(import_effect.Effect.service(import_effect.Logger.CurrentLoggers)).pipe(import_effect.Effect.orDie);
130
+ const logLevel = yield* applyEnv(import_effect.Effect.service(import_effect.References.MinimumLogLevel)).pipe(import_effect.Effect.orDie);
134
131
  const debugSinks = yield* applyEnv(
135
- import_effect.FiberRef.get(Logix.Debug.internal.currentDebugSinks)
132
+ import_effect.Effect.service(Logix.Debug.internal.currentDebugSinks).pipe(import_effect.Effect.orDie)
136
133
  );
137
134
  return { context, loggers, logLevel, debugSinks };
138
135
  });
@@ -177,7 +174,7 @@ var useLayerBinding = (runtime, layer, enabled, onError) => {
177
174
  const cause = import_effect.Cause.die(error);
178
175
  runtime.runFork(
179
176
  onError(cause, { source: "provider", phase: "provider.layer.build" }).pipe(
180
- import_effect.Effect.catchAllCause(() => import_effect.Effect.void)
177
+ import_effect.Effect.catchCause(() => import_effect.Effect.void)
181
178
  )
182
179
  );
183
180
  }
@@ -215,18 +212,11 @@ var createRuntimeAdapter = (runtime, contexts, scopes, loggerSets, logLevels, de
215
212
  if (contexts.length === 0 && scopes.length === 0 && loggerSets.length === 0 && logLevels.length === 0 && debugSinks.length === 0) {
216
213
  return runtime;
217
214
  }
218
- const applyContexts = (effect) => (
219
- // First inherit Provider scopes via scope.extend (preserving FiberRef/Logger changes),
220
- // then merge Context via mapInputContext (inner overrides outer).
221
- contexts.reduceRight(
222
- (acc, ctx) => import_effect.Effect.mapInputContext(
223
- acc,
224
- (parent) => import_effect.Context.merge(parent, ctx)
225
- ),
226
- scopes.reduceRight(
227
- (acc, scope) => import_effect.Scope.extend(acc, scope),
228
- effect
229
- )
215
+ const applyContexts = (effect) => contexts.reduceRight(
216
+ (acc, ctx) => import_effect.Effect.provideServices(acc, ctx),
217
+ scopes.reduceRight(
218
+ (acc, scope) => import_effect.Scope.provide(scope)(acc),
219
+ effect
230
220
  )
231
221
  );
232
222
  const applyLoggers = (effect) => {
@@ -235,16 +225,13 @@ var createRuntimeAdapter = (runtime, contexts, scopes, loggerSets, logLevels, de
235
225
  const sinks = debugSinks.length > 0 ? debugSinks[debugSinks.length - 1] : null;
236
226
  let result = effect;
237
227
  if (last) {
238
- result = import_effect.Effect.locally(import_effect.FiberRef.currentLoggers, last)(result);
228
+ result = import_effect.Effect.provideService(result, import_effect.Logger.CurrentLoggers, last);
239
229
  }
240
230
  if (logLevel) {
241
- result = import_effect.Effect.locally(import_effect.FiberRef.currentLogLevel, logLevel)(result);
231
+ result = import_effect.Effect.provideService(result, import_effect.References.MinimumLogLevel, logLevel);
242
232
  }
243
233
  if (sinks && sinks.length > 0) {
244
- result = import_effect.Effect.locally(
245
- Logix.Debug.internal.currentDebugSinks,
246
- sinks
247
- )(result);
234
+ result = import_effect.Effect.provideService(result, Logix.Debug.internal.currentDebugSinks, sinks);
248
235
  }
249
236
  return result;
250
237
  };
@@ -336,13 +323,13 @@ function useRuntime(options) {
336
323
 
337
324
  // src/internal/hooks/useModule.ts
338
325
  var import_react7 = __toESM(require("react"), 1);
339
- var Logix7 = __toESM(require("@logixjs/core"), 1);
326
+ var Logix9 = __toESM(require("@logixjs/core"), 1);
340
327
  var import_effect8 = require("effect");
341
328
 
342
329
  // src/internal/hooks/useModuleRuntime.ts
343
330
  var import_react4 = require("react");
344
- var Logix4 = __toESM(require("@logixjs/core"), 1);
345
- var import_effect5 = require("effect");
331
+ var Logix5 = __toESM(require("@logixjs/core"), 1);
332
+ var import_effect6 = require("effect");
346
333
 
347
334
  // src/internal/store/ModuleRef.ts
348
335
  var isModuleRef = (value) => typeof value === "object" && value !== null && "runtime" in value && "actions" in value && "dispatch" in value;
@@ -433,27 +420,41 @@ var applyHandleExtend = (tag, runtime, base) => {
433
420
  return { ...base, ...next };
434
421
  };
435
422
 
423
+ // src/internal/provider/runtimeDebugBridge.ts
424
+ var import_effect3 = require("effect");
425
+ var Logix2 = __toESM(require("@logixjs/core"), 1);
426
+ var readRuntimeDiagnosticsLevel = (runtime) => {
427
+ try {
428
+ return runtime.runSync(import_effect3.Effect.service(Logix2.Debug.internal.currentDiagnosticsLevel).pipe(import_effect3.Effect.orDie));
429
+ } catch {
430
+ return (0, import_Env.isDevEnv)() ? "light" : "off";
431
+ }
432
+ };
433
+ var emitRuntimeDebugEventBestEffort = (runtime, event) => {
434
+ runtime.runFork(event);
435
+ };
436
+
436
437
  // src/internal/store/ModuleCache.ts
437
- var Logix3 = __toESM(require("@logixjs/core"), 1);
438
- var import_effect4 = require("effect");
438
+ var Logix4 = __toESM(require("@logixjs/core"), 1);
439
+ var import_effect5 = require("effect");
439
440
 
440
441
  // src/internal/store/perfWorkloads.ts
441
- var Logix2 = __toESM(require("@logixjs/core"), 1);
442
- var import_effect3 = require("effect");
443
- var PerfCounterStateSchema = import_effect3.Schema.Struct({
444
- value: import_effect3.Schema.Number
442
+ var Logix3 = __toESM(require("@logixjs/core"), 1);
443
+ var import_effect4 = require("effect");
444
+ var PerfCounterStateSchema = import_effect4.Schema.Struct({
445
+ value: import_effect4.Schema.Number
445
446
  });
446
447
  var PerfCounterActions = {
447
- inc: import_effect3.Schema.Void
448
+ inc: import_effect4.Schema.Void
448
449
  };
449
- var PerfListScopeRowSchema = import_effect3.Schema.Struct({
450
- id: import_effect3.Schema.String,
451
- warehouseId: import_effect3.Schema.String
450
+ var PerfListScopeRowSchema = import_effect4.Schema.Struct({
451
+ id: import_effect4.Schema.String,
452
+ warehouseId: import_effect4.Schema.String
452
453
  });
453
- var PerfListScopeStateSchema = import_effect3.Schema.Struct({
454
- items: import_effect3.Schema.Array(PerfListScopeRowSchema),
455
- digest: import_effect3.Schema.String,
456
- errors: import_effect3.Schema.Any
454
+ var PerfListScopeStateSchema = import_effect4.Schema.Struct({
455
+ items: import_effect4.Schema.Array(PerfListScopeRowSchema),
456
+ digest: import_effect4.Schema.String,
457
+ errors: import_effect4.Schema.Any
457
458
  });
458
459
  var GLOBAL_YIELD_BUDGET_MEMORY_KEY = "__LOGIX_REACT_YIELD_BUDGET_MEMORY__";
459
460
  var getGlobalYieldBudgetMemory = () => {
@@ -548,20 +549,20 @@ ${message}`;
548
549
  console.debug(label, message);
549
550
  };
550
551
  var causeToUnknown = (cause) => {
551
- const failure = import_effect4.Option.getOrUndefined(import_effect4.Cause.failureOption(cause));
552
+ const failure = import_effect5.Option.getOrUndefined(import_effect5.Cause.findErrorOption(cause));
552
553
  if (failure !== void 0) return failure;
553
- const defect = import_effect4.Option.getOrUndefined(import_effect4.Cause.dieOption(cause));
554
+ const defect = cause.reasons.filter(import_effect5.Cause.isDieReason).map((reason) => reason.defect)[0];
554
555
  if (defect !== void 0) return defect;
555
556
  return cause;
556
557
  };
557
558
  var yieldEffect = (strategy) => {
558
559
  switch (strategy) {
559
560
  case "none":
560
- return import_effect4.Effect.void;
561
+ return import_effect5.Effect.void;
561
562
  case "microtask":
562
- return import_effect4.Effect.yieldNow();
563
+ return import_effect5.Effect.yieldNow;
563
564
  case "macrotask":
564
- return import_effect4.Effect.promise(
565
+ return import_effect5.Effect.promise(
565
566
  () => new Promise((resolve) => {
566
567
  setTimeout(resolve, 0);
567
568
  })
@@ -609,11 +610,11 @@ var ModuleCache = class {
609
610
  this.scheduleGC(key, current);
610
611
  return;
611
612
  }
612
- void this.runtime.runPromise(import_effect4.Scope.close(current.scope, import_effect4.Exit.void)).catch((error) => {
613
+ void this.runtime.runPromise(import_effect5.Scope.close(current.scope, import_effect5.Exit.void)).catch((error) => {
613
614
  debugBestEffortFailure("[ModuleCache] Scope.close failed", error);
614
615
  });
615
616
  void this.runtime.runPromise(
616
- Logix3.Debug.record({
617
+ Logix4.Debug.record({
617
618
  type: "trace:react.module-instance",
618
619
  moduleId: current.ownerId,
619
620
  instanceId: current.value?.instanceId,
@@ -649,9 +650,70 @@ var ModuleCache = class {
649
650
  }
650
651
  return existing.value;
651
652
  }
652
- const scope = import_effect4.Effect.runSync(import_effect4.Scope.make());
653
+ const scope = import_effect5.Effect.runSync(import_effect5.Scope.make());
653
654
  const workloadKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`;
654
655
  const yieldDecision = decideYieldStrategy(this.runtime, workloadKey, options?.yield);
656
+ const optimisticSyncBudgetMs = options?.optimisticSyncBudgetMs ?? 0;
657
+ const shouldTryOptimisticSync = options?.policyMode === "suspend" && optimisticSyncBudgetMs > 0;
658
+ if (shouldTryOptimisticSync) {
659
+ const startedAt2 = performance.now();
660
+ try {
661
+ const value = this.runtime.runSync(factory(scope));
662
+ const durationMs = performance.now() - startedAt2;
663
+ YieldBudgetMemory.record({ runtime: this.runtime, workloadKey, durationMs });
664
+ const entry2 = {
665
+ scope,
666
+ status: "success",
667
+ promise: Promise.resolve(value),
668
+ value,
669
+ refCount: 0,
670
+ preloadRefCount: 0,
671
+ gcTime: gcTime ?? this.gcDelayMs,
672
+ ownerId,
673
+ createdBy: "read",
674
+ workloadKey,
675
+ yieldStrategy: "none"
676
+ };
677
+ this.scheduleGC(key, entry2);
678
+ this.entries.set(key, entry2);
679
+ if ((0, import_Env.isDevEnv)() || Logix4.Debug.isDevtoolsEnabled()) {
680
+ void this.runtime.runPromise(
681
+ Logix4.Debug.record({
682
+ type: "trace:react.module.init",
683
+ moduleId: ownerId,
684
+ instanceId: value.instanceId,
685
+ data: {
686
+ mode: "suspend",
687
+ key,
688
+ durationMs: Math.round(durationMs * 100) / 100,
689
+ yieldStrategy: "none",
690
+ fastPath: "sync"
691
+ }
692
+ })
693
+ ).catch((error) => {
694
+ debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
695
+ });
696
+ void this.runtime.runPromise(
697
+ Logix4.Debug.record({
698
+ type: "trace:react.module-instance",
699
+ moduleId: ownerId,
700
+ instanceId: value.instanceId,
701
+ data: {
702
+ event: "attach",
703
+ key,
704
+ mode: "suspend",
705
+ gcTime: entry2.gcTime,
706
+ fastPath: "sync"
707
+ }
708
+ })
709
+ ).catch((error) => {
710
+ debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
711
+ });
712
+ }
713
+ return value;
714
+ } catch {
715
+ }
716
+ }
655
717
  const entry = {
656
718
  scope,
657
719
  status: "pending",
@@ -667,11 +729,11 @@ var ModuleCache = class {
667
729
  };
668
730
  this.scheduleGC(key, entry);
669
731
  const startedAt = performance.now();
670
- const buildEffect = yieldEffect(yieldDecision.strategy).pipe(import_effect4.Effect.zipRight(factory(scope)));
732
+ const buildEffect = yieldEffect(yieldDecision.strategy).pipe(import_effect5.Effect.flatMap(() => factory(scope)));
671
733
  const fiber = this.runtime.runFork(buildEffect);
672
734
  entry.fiber = fiber;
673
- const promise = this.runtime.runPromise(import_effect4.Fiber.await(fiber)).then((exit) => {
674
- if (import_effect4.Exit.isSuccess(exit)) return exit.value;
735
+ const promise = this.runtime.runPromise(import_effect5.Fiber.await(fiber)).then((exit) => {
736
+ if (import_effect5.Exit.isSuccess(exit)) return exit.value;
675
737
  throw causeToUnknown(exit.cause);
676
738
  });
677
739
  promise.then((value) => {
@@ -679,9 +741,9 @@ var ModuleCache = class {
679
741
  entry.value = value;
680
742
  const durationMs = performance.now() - startedAt;
681
743
  YieldBudgetMemory.record({ runtime: this.runtime, workloadKey, durationMs });
682
- if ((0, import_Env.isDevEnv)() || Logix3.Debug.isDevtoolsEnabled()) {
744
+ if ((0, import_Env.isDevEnv)() || Logix4.Debug.isDevtoolsEnabled()) {
683
745
  void this.runtime.runPromise(
684
- Logix3.Debug.record({
746
+ Logix4.Debug.record({
685
747
  type: "trace:react.module.init",
686
748
  moduleId: ownerId,
687
749
  instanceId: value.instanceId,
@@ -698,7 +760,7 @@ var ModuleCache = class {
698
760
  debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
699
761
  });
700
762
  void this.runtime.runPromise(
701
- Logix3.Debug.record({
763
+ Logix4.Debug.record({
702
764
  type: "trace:react.module-instance",
703
765
  moduleId: ownerId,
704
766
  instanceId: value.instanceId,
@@ -728,7 +790,7 @@ var ModuleCache = class {
728
790
  workloadKey,
729
791
  durationMs: performance.now() - startedAt
730
792
  });
731
- void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
793
+ void this.runtime.runPromise(import_effect5.Scope.close(scope, import_effect5.Exit.fail(error))).catch((closeError) => {
732
794
  debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
733
795
  });
734
796
  throw error;
@@ -760,7 +822,7 @@ var ModuleCache = class {
760
822
  }
761
823
  return existing.value;
762
824
  }
763
- const scope = this.runtime.runSync(import_effect4.Scope.make());
825
+ const scope = this.runtime.runSync(import_effect5.Scope.make());
764
826
  const startedAt = performance.now();
765
827
  try {
766
828
  const value = this.runtime.runSync(factory(scope));
@@ -808,9 +870,9 @@ var ModuleCache = class {
808
870
  }
809
871
  }
810
872
  }
811
- if ((0, import_Env.isDevEnv)() || Logix3.Debug.isDevtoolsEnabled()) {
873
+ if ((0, import_Env.isDevEnv)() || Logix4.Debug.isDevtoolsEnabled()) {
812
874
  void this.runtime.runPromise(
813
- Logix3.Debug.record({
875
+ Logix4.Debug.record({
814
876
  type: "trace:react.module.init",
815
877
  moduleId: ownerId,
816
878
  instanceId: value.instanceId,
@@ -825,7 +887,7 @@ var ModuleCache = class {
825
887
  debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
826
888
  });
827
889
  void this.runtime.runPromise(
828
- Logix3.Debug.record({
890
+ Logix4.Debug.record({
829
891
  type: "trace:react.module-instance",
830
892
  moduleId: ownerId,
831
893
  instanceId: value.instanceId,
@@ -842,7 +904,7 @@ var ModuleCache = class {
842
904
  }
843
905
  return value;
844
906
  } catch (error) {
845
- void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
907
+ void this.runtime.runPromise(import_effect5.Scope.close(scope, import_effect5.Exit.fail(error))).catch((closeError) => {
846
908
  debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
847
909
  });
848
910
  const entry = {
@@ -863,6 +925,49 @@ var ModuleCache = class {
863
925
  throw error;
864
926
  }
865
927
  }
928
+ warmSync(key, factory, gcTime, ownerId, options) {
929
+ const existing = this.entries.get(key);
930
+ if (existing) {
931
+ if ((0, import_Env.isDevEnv)() && existing.ownerId !== void 0 && ownerId !== void 0 && existing.ownerId !== ownerId) {
932
+ throw new Error(
933
+ `[ModuleCache.warmSync] resource key "${key}" has already been claimed by module "${existing.ownerId}", but is now requested by module "${ownerId}".`
934
+ );
935
+ }
936
+ if (existing.status === "success") {
937
+ return existing.value;
938
+ }
939
+ return void 0;
940
+ }
941
+ const scope = this.runtime.runSync(import_effect5.Scope.make());
942
+ const startedAt = performance.now();
943
+ const workloadKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`;
944
+ try {
945
+ const value = this.runtime.runSync(factory(scope));
946
+ const durationMs = performance.now() - startedAt;
947
+ YieldBudgetMemory.record({ runtime: this.runtime, workloadKey, durationMs });
948
+ const entry = {
949
+ scope,
950
+ status: "success",
951
+ promise: Promise.resolve(value),
952
+ value,
953
+ refCount: 0,
954
+ preloadRefCount: 0,
955
+ gcTime: gcTime ?? this.gcDelayMs,
956
+ ownerId,
957
+ createdBy: "preload",
958
+ workloadKey,
959
+ yieldStrategy: "none"
960
+ };
961
+ this.scheduleGC(key, entry);
962
+ this.entries.set(key, entry);
963
+ return value;
964
+ } catch (error) {
965
+ void this.runtime.runPromise(import_effect5.Scope.close(scope, import_effect5.Exit.fail(error))).catch((closeError) => {
966
+ debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
967
+ });
968
+ return void 0;
969
+ }
970
+ }
866
971
  preload(key, factory, options) {
867
972
  const existing = this.entries.get(key);
868
973
  if (existing) {
@@ -887,11 +992,43 @@ var ModuleCache = class {
887
992
  }
888
993
  };
889
994
  }
890
- const scope = import_effect4.Effect.runSync(import_effect4.Scope.make());
995
+ const scope = import_effect5.Effect.runSync(import_effect5.Scope.make());
891
996
  const ownerId = options?.ownerId;
892
997
  const gcTime = options?.gcTime ?? this.gcDelayMs;
893
998
  const workloadKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`;
894
999
  const yieldDecision = decideYieldStrategy(this.runtime, workloadKey, options?.yield);
1000
+ const optimisticSyncBudgetMs = options?.optimisticSyncBudgetMs ?? 0;
1001
+ const shouldTryOptimisticSync = options?.policyMode === "defer" && optimisticSyncBudgetMs > 0;
1002
+ if (shouldTryOptimisticSync) {
1003
+ const startedAt2 = performance.now();
1004
+ try {
1005
+ const value = this.runtime.runSync(factory(scope));
1006
+ const durationMs = performance.now() - startedAt2;
1007
+ YieldBudgetMemory.record({ runtime: this.runtime, workloadKey, durationMs });
1008
+ const entry2 = {
1009
+ scope,
1010
+ status: "success",
1011
+ promise: Promise.resolve(value),
1012
+ value,
1013
+ refCount: 0,
1014
+ preloadRefCount: 1,
1015
+ gcTime,
1016
+ ownerId,
1017
+ createdBy: "preload",
1018
+ workloadKey,
1019
+ yieldStrategy: "none"
1020
+ };
1021
+ this.scheduleGC(key, entry2);
1022
+ this.entries.set(key, entry2);
1023
+ return {
1024
+ promise: Promise.resolve(value),
1025
+ cancel: () => {
1026
+ this.cancelPreload(key, entry2);
1027
+ }
1028
+ };
1029
+ } catch {
1030
+ }
1031
+ }
895
1032
  const entry = {
896
1033
  scope,
897
1034
  status: "pending",
@@ -907,11 +1044,11 @@ var ModuleCache = class {
907
1044
  this.scheduleGC(key, entry);
908
1045
  this.entries.set(key, entry);
909
1046
  const startedAt = performance.now();
910
- const buildEffect = yieldEffect(yieldDecision.strategy).pipe(import_effect4.Effect.zipRight(factory(scope)));
1047
+ const buildEffect = yieldEffect(yieldDecision.strategy).pipe(import_effect5.Effect.flatMap(() => factory(scope)));
911
1048
  const fiber = this.runtime.runFork(buildEffect);
912
1049
  entry.fiber = fiber;
913
- const promise = this.runtime.runPromise(import_effect4.Fiber.await(fiber)).then((exit) => {
914
- if (import_effect4.Exit.isSuccess(exit)) return exit.value;
1050
+ const promise = this.runtime.runPromise(import_effect5.Fiber.await(fiber)).then((exit) => {
1051
+ if (import_effect5.Exit.isSuccess(exit)) return exit.value;
915
1052
  throw causeToUnknown(exit.cause);
916
1053
  });
917
1054
  entry.promise = promise;
@@ -937,7 +1074,7 @@ var ModuleCache = class {
937
1074
  workloadKey,
938
1075
  durationMs: performance.now() - startedAt
939
1076
  });
940
- void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
1077
+ void this.runtime.runPromise(import_effect5.Scope.close(scope, import_effect5.Exit.fail(error))).catch((closeError) => {
941
1078
  debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
942
1079
  });
943
1080
  });
@@ -969,9 +1106,9 @@ var ModuleCache = class {
969
1106
  entry.fiber = void 0;
970
1107
  this.entries.delete(key);
971
1108
  if (running) {
972
- this.runtime.runFork(import_effect4.Fiber.interrupt(running));
1109
+ this.runtime.runFork(import_effect5.Fiber.interrupt(running));
973
1110
  }
974
- void this.runtime.runPromise(import_effect4.Scope.close(entry.scope, import_effect4.Exit.void)).catch((closeError) => {
1111
+ void this.runtime.runPromise(import_effect5.Scope.close(entry.scope, import_effect5.Exit.void)).catch((closeError) => {
975
1112
  debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
976
1113
  });
977
1114
  return;
@@ -1017,7 +1154,7 @@ var ModuleCache = class {
1017
1154
  if (entry.gcTimeout) {
1018
1155
  clearTimeout(entry.gcTimeout);
1019
1156
  }
1020
- void this.runtime.runPromise(import_effect4.Scope.close(entry.scope, import_effect4.Exit.void)).catch((error) => {
1157
+ void this.runtime.runPromise(import_effect5.Scope.close(entry.scope, import_effect5.Exit.void)).catch((error) => {
1021
1158
  debugBestEffortFailure("[ModuleCache] Scope.close failed", error);
1022
1159
  });
1023
1160
  this.entries.delete(key);
@@ -1073,6 +1210,7 @@ var isModuleRuntime = (value) => typeof value === "object" && value !== null &&
1073
1210
  function useModuleRuntime(handle) {
1074
1211
  const runtime = useRuntime();
1075
1212
  const runtimeContext = (0, import_react4.useContext)(RuntimeContext);
1213
+ const moduleTagResolveTraceRef = (0, import_react4.useRef)(void 0);
1076
1214
  if (!runtimeContext) {
1077
1215
  throw new RuntimeProviderNotFoundError("useModuleRuntime");
1078
1216
  }
@@ -1093,36 +1231,48 @@ function useModuleRuntime(handle) {
1093
1231
  const preloadKey = runtimeContext.policy.preload?.keysByTagId.get(tokenId);
1094
1232
  const key = preloadKey ?? `tag:${tokenId}`;
1095
1233
  const mode = runtimeContext.policy.moduleTagMode;
1096
- const factory = (scope) => tag.pipe(import_effect5.Scope.extend(scope));
1097
- return mode === "suspend" ? cache.read(key, factory, void 0, tokenId, {
1234
+ const startedAtMs = performance.now();
1235
+ const factory = (scope) => import_effect6.Scope.provide(scope)(import_effect6.Effect.service(tag).pipe(import_effect6.Effect.orDie));
1236
+ const resolvedRuntime = mode === "suspend" ? cache.read(key, factory, void 0, tokenId, {
1098
1237
  entrypoint: "react.useModuleRuntime",
1099
1238
  policyMode: runtimeContext.policy.mode,
1100
- yield: runtimeContext.policy.yield
1239
+ yield: runtimeContext.policy.yield,
1240
+ optimisticSyncBudgetMs: runtimeContext.policy.syncBudgetMs
1101
1241
  }) : cache.readSync(key, factory, void 0, tokenId, {
1102
1242
  entrypoint: "react.useModuleRuntime",
1103
1243
  policyMode: runtimeContext.policy.mode,
1104
1244
  warnSyncBlockingThresholdMs: 5
1105
1245
  });
1246
+ moduleTagResolveTraceRef.current = {
1247
+ tokenId,
1248
+ durationMs: Math.round((performance.now() - startedAtMs) * 100) / 100,
1249
+ cacheMode: mode
1250
+ };
1251
+ return resolvedRuntime;
1106
1252
  }, [cache, runtimeContext.policy, handle]);
1107
1253
  (0, import_react4.useEffect)(() => {
1108
1254
  if (!isTagHandle) {
1109
1255
  return;
1110
1256
  }
1111
- if (!(0, import_Env.isDevEnv)() && !Logix4.Debug.isDevtoolsEnabled()) {
1257
+ const diagnosticsLevel = readRuntimeDiagnosticsLevel(runtime);
1258
+ if (diagnosticsLevel === "off") {
1112
1259
  return;
1113
1260
  }
1114
1261
  const tokenId = handle?.id ?? "ModuleTag";
1115
- const effect = Logix4.Debug.record({
1262
+ const trace = moduleTagResolveTraceRef.current;
1263
+ const effect = Logix5.Debug.record({
1116
1264
  type: "trace:react.moduleTag.resolve",
1117
1265
  moduleId: resolved.moduleId,
1118
1266
  instanceId: resolved.instanceId,
1119
1267
  data: {
1120
1268
  mode: runtimeContext.policy.moduleTagMode,
1121
1269
  tokenId,
1122
- yieldStrategy: runtimeContext.policy.yield.strategy
1270
+ yieldStrategy: runtimeContext.policy.yield.strategy,
1271
+ durationMs: trace?.durationMs,
1272
+ cacheMode: trace?.cacheMode ?? runtimeContext.policy.moduleTagMode
1123
1273
  }
1124
1274
  });
1125
- runtime.runFork(effect);
1275
+ emitRuntimeDebugEventBestEffort(runtime, effect);
1126
1276
  }, [runtime, runtimeContext.policy, resolved, handle, isTagHandle]);
1127
1277
  return resolved;
1128
1278
  }
@@ -1130,55 +1280,73 @@ function useModuleRuntime(handle) {
1130
1280
  // src/internal/hooks/useSelector.ts
1131
1281
  var import_react5 = require("react");
1132
1282
  var import_with_selector = require("use-sync-external-store/shim/with-selector");
1133
- var Logix5 = __toESM(require("@logixjs/core"), 1);
1283
+ var Logix7 = __toESM(require("@logixjs/core"), 1);
1134
1284
 
1135
- // src/internal/store/ModuleRuntimeExternalStore.ts
1136
- var import_effect6 = require("effect");
1285
+ // src/internal/store/RuntimeExternalStore.ts
1286
+ var Logix6 = __toESM(require("@logixjs/core"), 1);
1287
+ var import_effect7 = require("effect");
1137
1288
  var storesByRuntime = /* @__PURE__ */ new WeakMap();
1138
1289
  var getStoreMapForRuntime = (runtime) => {
1139
1290
  const cached = storesByRuntime.get(runtime);
1140
1291
  if (cached) return cached;
1141
- const next = /* @__PURE__ */ new WeakMap();
1292
+ const next = /* @__PURE__ */ new Map();
1142
1293
  storesByRuntime.set(runtime, next);
1143
1294
  return next;
1144
1295
  };
1145
- var getModuleRuntimeExternalStore = (runtime, moduleRuntime, options) => {
1146
- const byModule = getStoreMapForRuntime(runtime);
1147
- const cached = byModule.get(moduleRuntime);
1296
+ var makeModuleInstanceKey = (moduleId, instanceId) => `${moduleId}::${instanceId}`;
1297
+ var makeReadQueryTopicKey = (moduleInstanceKey, selectorId) => `${moduleInstanceKey}::rq:${selectorId}`;
1298
+ var getRuntimeStore = (runtime) => Logix6.InternalContracts.getRuntimeStore(runtime);
1299
+ var getHostScheduler = (runtime) => Logix6.InternalContracts.getHostScheduler(runtime);
1300
+ var getOrCreateStore = (runtime, topicKey, make) => {
1301
+ const map = getStoreMapForRuntime(runtime);
1302
+ const cached = map.get(topicKey);
1148
1303
  if (cached) {
1149
1304
  return cached;
1150
1305
  }
1151
- let currentState;
1306
+ const created = make();
1307
+ map.set(topicKey, created);
1308
+ return created;
1309
+ };
1310
+ var removeStore = (runtime, topicKey) => {
1311
+ const map = storesByRuntime.get(runtime);
1312
+ if (!map) return;
1313
+ map.delete(topicKey);
1314
+ };
1315
+ var makeTopicExternalStore = (args) => {
1316
+ const { runtime, runtimeStore, topicKey } = args;
1317
+ const hostScheduler = getHostScheduler(runtime);
1318
+ let currentVersion;
1319
+ let hasSnapshot = false;
1320
+ let currentSnapshot;
1152
1321
  const listeners = /* @__PURE__ */ new Set();
1153
- const lowPriorityDelayMs = options?.lowPriorityDelayMs ?? 16;
1154
- const lowPriorityMaxDelayMs = options?.lowPriorityMaxDelayMs ?? 50;
1322
+ let unsubscribeFromRuntimeStore;
1323
+ let teardownScheduled = false;
1324
+ let teardownToken = 0;
1325
+ const lowPriorityDelayMs = args.options?.lowPriorityDelayMs ?? 16;
1326
+ const lowPriorityMaxDelayMs = args.options?.lowPriorityMaxDelayMs ?? 50;
1155
1327
  let notifyScheduled = false;
1156
1328
  let notifyScheduledLow = false;
1157
- let lowTimeoutId;
1158
- let lowMaxTimeoutId;
1159
- let lowRafId;
1329
+ let lowCancelDelay;
1330
+ let lowCancelMaxDelay;
1331
+ let lowCancelRaf;
1160
1332
  const cancelLow = () => {
1161
1333
  if (!notifyScheduledLow) return;
1162
1334
  notifyScheduledLow = false;
1163
- if (lowTimeoutId != null) {
1164
- clearTimeout(lowTimeoutId);
1165
- lowTimeoutId = void 0;
1166
- }
1167
- if (lowMaxTimeoutId != null) {
1168
- clearTimeout(lowMaxTimeoutId);
1169
- lowMaxTimeoutId = void 0;
1170
- }
1171
- const cancel = globalThis.cancelAnimationFrame;
1172
- if (cancel && typeof lowRafId === "number") {
1173
- cancel(lowRafId);
1174
- lowRafId = void 0;
1175
- }
1335
+ lowCancelDelay?.();
1336
+ lowCancelDelay = void 0;
1337
+ lowCancelMaxDelay?.();
1338
+ lowCancelMaxDelay = void 0;
1339
+ lowCancelRaf?.();
1340
+ lowCancelRaf = void 0;
1176
1341
  };
1177
1342
  const flushNotify = () => {
1178
1343
  notifyScheduled = false;
1179
1344
  cancelLow();
1180
1345
  for (const listener of listeners) {
1181
- listener();
1346
+ try {
1347
+ listener();
1348
+ } catch {
1349
+ }
1182
1350
  }
1183
1351
  };
1184
1352
  const scheduleNotify = (priority) => {
@@ -1190,72 +1358,155 @@ var getModuleRuntimeExternalStore = (runtime, moduleRuntime, options) => {
1190
1358
  if (!notifyScheduledLow) return;
1191
1359
  flushNotify();
1192
1360
  };
1193
- const raf = globalThis.requestAnimationFrame;
1194
- if (raf) {
1195
- lowRafId = raf(flush);
1361
+ const scheduleRaf = () => {
1362
+ if (!notifyScheduledLow) return;
1363
+ lowCancelRaf = hostScheduler.scheduleAnimationFrame(flush);
1364
+ };
1365
+ if (lowPriorityDelayMs <= 0) {
1366
+ scheduleRaf();
1196
1367
  } else {
1197
- lowTimeoutId = setTimeout(flush, lowPriorityDelayMs);
1368
+ lowCancelDelay = hostScheduler.scheduleTimeout(lowPriorityDelayMs, scheduleRaf);
1198
1369
  }
1199
- lowMaxTimeoutId = setTimeout(flush, lowPriorityMaxDelayMs);
1370
+ lowCancelMaxDelay = hostScheduler.scheduleTimeout(lowPriorityMaxDelayMs, flush);
1200
1371
  return;
1201
1372
  }
1202
1373
  cancelLow();
1203
1374
  if (notifyScheduled) return;
1204
1375
  notifyScheduled = true;
1205
- queueMicrotask(flushNotify);
1376
+ hostScheduler.scheduleMicrotask(flushNotify);
1377
+ };
1378
+ const onRuntimeStoreChange = () => {
1379
+ try {
1380
+ scheduleNotify(runtimeStore.getTopicPriority(topicKey));
1381
+ } catch {
1382
+ }
1206
1383
  };
1207
- let fiber;
1208
1384
  const ensureSubscription = () => {
1209
- if (fiber) return;
1210
- fiber = runtime.runFork(
1211
- import_effect6.Stream.runForEach(
1212
- moduleRuntime.changesWithMeta((state) => state),
1213
- ({ value: state, meta }) => import_effect6.Effect.sync(() => {
1214
- currentState = state;
1215
- scheduleNotify(meta.priority);
1216
- })
1217
- )
1218
- );
1385
+ if (unsubscribeFromRuntimeStore) return;
1386
+ unsubscribeFromRuntimeStore = runtimeStore.subscribeTopic(topicKey, onRuntimeStoreChange);
1219
1387
  };
1220
1388
  const refreshSnapshotIfStale = () => {
1221
- if (currentState === void 0) {
1222
- return;
1223
- }
1389
+ if (!hasSnapshot) return;
1224
1390
  try {
1225
- const latest = runtime.runSync(moduleRuntime.getState);
1226
- if (currentState === void 0 || !Object.is(currentState, latest)) {
1227
- currentState = latest;
1228
- scheduleNotify("normal");
1391
+ const version = runtimeStore.getTopicVersion(topicKey);
1392
+ if (currentVersion !== version) {
1393
+ scheduleNotify(runtimeStore.getTopicPriority(topicKey));
1229
1394
  }
1230
1395
  } catch {
1231
1396
  }
1232
1397
  };
1233
1398
  const getSnapshot = () => {
1234
- if (currentState !== void 0) return currentState;
1235
- currentState = runtime.runSync(moduleRuntime.getState);
1236
- return currentState;
1399
+ const version = runtimeStore.getTopicVersion(topicKey);
1400
+ if (hasSnapshot && currentVersion === version) {
1401
+ return currentSnapshot;
1402
+ }
1403
+ const next = args.readSnapshot();
1404
+ currentVersion = version;
1405
+ hasSnapshot = true;
1406
+ currentSnapshot = next;
1407
+ return next;
1408
+ };
1409
+ const cancelScheduledTeardown = () => {
1410
+ if (!teardownScheduled) return;
1411
+ teardownScheduled = false;
1412
+ teardownToken += 1;
1413
+ };
1414
+ const finalizeTeardown = () => {
1415
+ if (listeners.size > 0) return;
1416
+ try {
1417
+ args.onLastListener?.();
1418
+ } catch {
1419
+ }
1420
+ const unsub = unsubscribeFromRuntimeStore;
1421
+ unsubscribeFromRuntimeStore = void 0;
1422
+ cancelLow();
1423
+ try {
1424
+ unsub?.();
1425
+ } catch {
1426
+ }
1427
+ removeStore(runtime, topicKey);
1428
+ };
1429
+ const scheduleTeardown = () => {
1430
+ if (teardownScheduled) return;
1431
+ teardownScheduled = true;
1432
+ const token = ++teardownToken;
1433
+ hostScheduler.scheduleMicrotask(() => {
1434
+ if (!teardownScheduled || token !== teardownToken) return;
1435
+ teardownScheduled = false;
1436
+ finalizeTeardown();
1437
+ });
1237
1438
  };
1238
1439
  const subscribe = (listener) => {
1440
+ cancelScheduledTeardown();
1441
+ const isFirst = listeners.size === 0;
1239
1442
  listeners.add(listener);
1240
1443
  ensureSubscription();
1241
1444
  refreshSnapshotIfStale();
1445
+ if (isFirst) {
1446
+ try {
1447
+ args.onFirstListener?.();
1448
+ } catch {
1449
+ }
1450
+ }
1242
1451
  return () => {
1243
1452
  listeners.delete(listener);
1244
1453
  if (listeners.size > 0) return;
1245
- const running = fiber;
1246
- if (!running) return;
1247
- fiber = void 0;
1248
- cancelLow();
1249
- runtime.runFork(import_effect6.Fiber.interrupt(running));
1454
+ scheduleTeardown();
1250
1455
  };
1251
1456
  };
1252
- const store = { getSnapshot, subscribe };
1253
- byModule.set(moduleRuntime, store);
1254
- return store;
1457
+ return { getSnapshot, getServerSnapshot: getSnapshot, subscribe };
1458
+ };
1459
+ var getRuntimeModuleExternalStore = (runtime, moduleRuntime, options) => {
1460
+ const moduleInstanceKey = makeModuleInstanceKey(moduleRuntime.moduleId, moduleRuntime.instanceId);
1461
+ const runtimeStore = getRuntimeStore(runtime);
1462
+ return getOrCreateStore(
1463
+ runtime,
1464
+ moduleInstanceKey,
1465
+ () => makeTopicExternalStore({
1466
+ runtime,
1467
+ runtimeStore,
1468
+ topicKey: moduleInstanceKey,
1469
+ readSnapshot: () => {
1470
+ const state = runtimeStore.getModuleState(moduleInstanceKey);
1471
+ if (state !== void 0) return state;
1472
+ return runtime.runSync(moduleRuntime.getState);
1473
+ },
1474
+ options
1475
+ })
1476
+ );
1477
+ };
1478
+ var getRuntimeReadQueryExternalStore = (runtime, moduleRuntime, selectorReadQuery, options) => {
1479
+ const moduleInstanceKey = makeModuleInstanceKey(moduleRuntime.moduleId, moduleRuntime.instanceId);
1480
+ const topicKey = makeReadQueryTopicKey(moduleInstanceKey, selectorReadQuery.selectorId);
1481
+ const runtimeStore = getRuntimeStore(runtime);
1482
+ let readQueryDrainFiber;
1483
+ return getOrCreateStore(
1484
+ runtime,
1485
+ topicKey,
1486
+ () => makeTopicExternalStore({
1487
+ runtime,
1488
+ runtimeStore,
1489
+ topicKey,
1490
+ readSnapshot: () => {
1491
+ const state = runtimeStore.getModuleState(moduleInstanceKey);
1492
+ const current = state ?? runtime.runSync(moduleRuntime.getState);
1493
+ return selectorReadQuery.select(current);
1494
+ },
1495
+ options,
1496
+ onFirstListener: () => {
1497
+ if (readQueryDrainFiber) return;
1498
+ const effect = import_effect7.Stream.runDrain(moduleRuntime.changesReadQueryWithMeta(selectorReadQuery));
1499
+ readQueryDrainFiber = runtime.runFork(effect);
1500
+ },
1501
+ onLastListener: () => {
1502
+ const fiber = readQueryDrainFiber;
1503
+ if (!fiber) return;
1504
+ readQueryDrainFiber = void 0;
1505
+ runtime.runFork(import_effect7.Fiber.interrupt(fiber));
1506
+ }
1507
+ })
1508
+ );
1255
1509
  };
1256
-
1257
- // src/internal/store/ModuleRuntimeSelectorExternalStore.ts
1258
- var import_effect7 = require("effect");
1259
1510
 
1260
1511
  // src/internal/hooks/shallow.ts
1261
1512
  var hasObjectShape = (value) => typeof value === "object" && value !== null;
@@ -1307,146 +1558,6 @@ var shallow = (previous, next) => {
1307
1558
  return true;
1308
1559
  };
1309
1560
 
1310
- // src/internal/store/ModuleRuntimeSelectorExternalStore.ts
1311
- var storesByRuntime2 = /* @__PURE__ */ new WeakMap();
1312
- var getStoreMapForRuntime2 = (runtime) => {
1313
- const cached = storesByRuntime2.get(runtime);
1314
- if (cached) return cached;
1315
- const next = /* @__PURE__ */ new WeakMap();
1316
- storesByRuntime2.set(runtime, next);
1317
- return next;
1318
- };
1319
- var getOrCreateSelectorMapForModule = (byModule, moduleRuntime) => {
1320
- const cached = byModule.get(moduleRuntime);
1321
- if (cached) return cached;
1322
- const next = /* @__PURE__ */ new Map();
1323
- byModule.set(moduleRuntime, next);
1324
- return next;
1325
- };
1326
- var equalsValue = (readQuery, a, b) => {
1327
- if (readQuery.equalsKind === "custom" && typeof readQuery.equals === "function") {
1328
- return readQuery.equals(a, b);
1329
- }
1330
- if (readQuery.equalsKind === "shallowStruct") {
1331
- return shallow(a, b);
1332
- }
1333
- return Object.is(a, b);
1334
- };
1335
- var getModuleRuntimeSelectorExternalStore = (runtime, moduleRuntime, selectorReadQuery, options) => {
1336
- const byModule = getStoreMapForRuntime2(runtime);
1337
- const bySelector = getOrCreateSelectorMapForModule(byModule, moduleRuntime);
1338
- const cached = bySelector.get(selectorReadQuery.selectorId);
1339
- if (cached) {
1340
- return cached;
1341
- }
1342
- let currentValue;
1343
- const listeners = /* @__PURE__ */ new Set();
1344
- const lowPriorityDelayMs = options?.lowPriorityDelayMs ?? 16;
1345
- const lowPriorityMaxDelayMs = options?.lowPriorityMaxDelayMs ?? 50;
1346
- let notifyScheduled = false;
1347
- let notifyScheduledLow = false;
1348
- let lowTimeoutId;
1349
- let lowMaxTimeoutId;
1350
- let lowRafId;
1351
- const cancelLow = () => {
1352
- if (!notifyScheduledLow) return;
1353
- notifyScheduledLow = false;
1354
- if (lowTimeoutId != null) {
1355
- clearTimeout(lowTimeoutId);
1356
- lowTimeoutId = void 0;
1357
- }
1358
- if (lowMaxTimeoutId != null) {
1359
- clearTimeout(lowMaxTimeoutId);
1360
- lowMaxTimeoutId = void 0;
1361
- }
1362
- const cancel = globalThis.cancelAnimationFrame;
1363
- if (cancel && typeof lowRafId === "number") {
1364
- cancel(lowRafId);
1365
- lowRafId = void 0;
1366
- }
1367
- };
1368
- const flushNotify = () => {
1369
- notifyScheduled = false;
1370
- cancelLow();
1371
- for (const listener of listeners) {
1372
- listener();
1373
- }
1374
- };
1375
- const scheduleNotify = (priority) => {
1376
- if (priority === "low") {
1377
- if (notifyScheduled) return;
1378
- if (notifyScheduledLow) return;
1379
- notifyScheduledLow = true;
1380
- const flush = () => {
1381
- if (!notifyScheduledLow) return;
1382
- flushNotify();
1383
- };
1384
- const raf = globalThis.requestAnimationFrame;
1385
- if (raf) {
1386
- lowRafId = raf(flush);
1387
- } else {
1388
- lowTimeoutId = setTimeout(flush, lowPriorityDelayMs);
1389
- }
1390
- lowMaxTimeoutId = setTimeout(flush, lowPriorityMaxDelayMs);
1391
- return;
1392
- }
1393
- cancelLow();
1394
- if (notifyScheduled) return;
1395
- notifyScheduled = true;
1396
- queueMicrotask(flushNotify);
1397
- };
1398
- let fiber;
1399
- const ensureSubscription = () => {
1400
- if (fiber) return;
1401
- fiber = runtime.runFork(
1402
- import_effect7.Stream.runForEach(
1403
- moduleRuntime.changesReadQueryWithMeta(selectorReadQuery),
1404
- ({ value, meta }) => import_effect7.Effect.sync(() => {
1405
- currentValue = value;
1406
- scheduleNotify(meta.priority);
1407
- })
1408
- )
1409
- );
1410
- };
1411
- const refreshSnapshotIfStale = () => {
1412
- if (currentValue === void 0) {
1413
- return;
1414
- }
1415
- try {
1416
- const state = runtime.runSync(moduleRuntime.getState);
1417
- const next = selectorReadQuery.select(state);
1418
- if (currentValue === void 0 || !equalsValue(selectorReadQuery, currentValue, next)) {
1419
- currentValue = next;
1420
- scheduleNotify("normal");
1421
- }
1422
- } catch {
1423
- }
1424
- };
1425
- const getSnapshot = () => {
1426
- if (currentValue !== void 0) return currentValue;
1427
- const state = runtime.runSync(moduleRuntime.getState);
1428
- currentValue = selectorReadQuery.select(state);
1429
- return currentValue;
1430
- };
1431
- const subscribe = (listener) => {
1432
- listeners.add(listener);
1433
- ensureSubscription();
1434
- refreshSnapshotIfStale();
1435
- return () => {
1436
- listeners.delete(listener);
1437
- if (listeners.size > 0) return;
1438
- const running = fiber;
1439
- if (!running) return;
1440
- fiber = void 0;
1441
- cancelLow();
1442
- runtime.runFork(import_effect7.Fiber.interrupt(running));
1443
- };
1444
- };
1445
- const store = { getSnapshot, subscribe };
1446
- bySelector.set(selectorReadQuery.selectorId, store);
1447
- return store;
1448
- };
1449
-
1450
1561
  // src/internal/hooks/useSelector.ts
1451
1562
  function useSelector(handle, selector, equalityFn) {
1452
1563
  const runtimeContext = (0, import_react5.useContext)(RuntimeContext);
@@ -1457,7 +1568,7 @@ function useSelector(handle, selector, equalityFn) {
1457
1568
  const moduleRuntime = useModuleRuntime(handle);
1458
1569
  const actualSelector = selector ?? ((state) => state);
1459
1570
  const selectorReadQuery = (0, import_react5.useMemo)(
1460
- () => typeof selector === "function" ? Logix5.ReadQuery.compile(selector) : void 0,
1571
+ () => typeof selector === "function" ? Logix7.ReadQuery.compile(selector) : void 0,
1461
1572
  [selector]
1462
1573
  );
1463
1574
  const actualEqualityFn = (0, import_react5.useMemo)(() => {
@@ -1465,17 +1576,12 @@ function useSelector(handle, selector, equalityFn) {
1465
1576
  if (typeof selector !== "function") return Object.is;
1466
1577
  return selectorReadQuery?.equalsKind === "shallowStruct" ? shallow : Object.is;
1467
1578
  }, [equalityFn, selector, selectorReadQuery?.equalsKind]);
1468
- const useStaticLane = typeof selector === "function" && selectorReadQuery?.lane === "static";
1579
+ const selectorTopicEligible = typeof selector === "function" && selectorReadQuery?.lane === "static" && selectorReadQuery.readsDigest != null && selectorReadQuery.fallbackReason == null;
1469
1580
  const store = (0, import_react5.useMemo)(
1470
- () => useStaticLane && selectorReadQuery ? getModuleRuntimeSelectorExternalStore(
1471
- runtime,
1472
- moduleRuntime,
1473
- selectorReadQuery,
1474
- {
1475
- lowPriorityDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
1476
- lowPriorityMaxDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs
1477
- }
1478
- ) : getModuleRuntimeExternalStore(
1581
+ () => selectorTopicEligible && selectorReadQuery ? getRuntimeReadQueryExternalStore(runtime, moduleRuntime, selectorReadQuery, {
1582
+ lowPriorityDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
1583
+ lowPriorityMaxDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs
1584
+ }) : getRuntimeModuleExternalStore(
1479
1585
  runtime,
1480
1586
  moduleRuntime,
1481
1587
  {
@@ -1489,18 +1595,18 @@ function useSelector(handle, selector, equalityFn) {
1489
1595
  runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
1490
1596
  runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs,
1491
1597
  selectorReadQuery,
1492
- useStaticLane
1598
+ selectorTopicEligible
1493
1599
  ]
1494
1600
  );
1495
1601
  const selected = (0, import_with_selector.useSyncExternalStoreWithSelector)(
1496
1602
  store.subscribe,
1497
1603
  store.getSnapshot,
1498
- store.getSnapshot,
1499
- useStaticLane ? (snapshot) => snapshot : (snapshot) => actualSelector(snapshot),
1604
+ store.getServerSnapshot ?? store.getSnapshot,
1605
+ selectorTopicEligible ? (snapshot) => snapshot : (snapshot) => actualSelector(snapshot),
1500
1606
  actualEqualityFn
1501
1607
  );
1502
1608
  (0, import_react5.useEffect)(() => {
1503
- if (!(0, import_Env.isDevEnv)() && !Logix5.Debug.isDevtoolsEnabled()) {
1609
+ if (!(0, import_Env.isDevEnv)() && !Logix7.Debug.isDevtoolsEnabled()) {
1504
1610
  return;
1505
1611
  }
1506
1612
  const instanceId = moduleRuntime.instanceId;
@@ -1516,7 +1622,7 @@ function useSelector(handle, selector, equalityFn) {
1516
1622
  const rawDebugKey = meta.debugKey;
1517
1623
  selectorKey = typeof rawDebugKey === "string" && rawDebugKey.length > 0 ? rawDebugKey : typeof selector.name === "string" && selector.name.length > 0 ? selector.name : void 0;
1518
1624
  }
1519
- const effect = Logix5.Debug.record({
1625
+ const effect = Logix7.Debug.record({
1520
1626
  type: "trace:react-selector",
1521
1627
  moduleId: moduleRuntime.moduleId,
1522
1628
  instanceId,
@@ -1539,7 +1645,7 @@ function useSelector(handle, selector, equalityFn) {
1539
1645
  }
1540
1646
 
1541
1647
  // src/internal/store/resolveImportedModuleRef.ts
1542
- var Logix6 = __toESM(require("@logixjs/core"), 1);
1648
+ var Logix8 = __toESM(require("@logixjs/core"), 1);
1543
1649
  var getOrCreateWeakMap = (map, key, make) => {
1544
1650
  const cached = map.get(key);
1545
1651
  if (cached) return cached;
@@ -1563,7 +1669,7 @@ var resolveImportedModuleRef = (runtime, parentRuntime, module2) => {
1563
1669
  if (cached) {
1564
1670
  return cached;
1565
1671
  }
1566
- const importsScope = Logix6.InternalContracts.getImportsScope(parentRuntime);
1672
+ const importsScope = Logix8.InternalContracts.getImportsScope(parentRuntime);
1567
1673
  const childRuntime = importsScope.get(module2);
1568
1674
  if (childRuntime) {
1569
1675
  const dispatch = Object.assign(
@@ -1649,8 +1755,8 @@ var useStableId = () => {
1649
1755
 
1650
1756
  // src/internal/hooks/useModule.ts
1651
1757
  var isModuleImpl = (handle) => Boolean(handle) && typeof handle === "object" && handle._tag === "ModuleImpl";
1652
- var isModule = (handle) => Logix7.Module.hasImpl(handle);
1653
- var isModuleDef = (handle) => Logix7.Module.is(handle) && handle._kind === "ModuleDef";
1758
+ var isModule = (handle) => Logix9.Module.hasImpl(handle);
1759
+ var isModuleDef = (handle) => Logix9.Module.is(handle) && handle._kind === "ModuleDef";
1654
1760
  function useModule(handle, selectorOrOptions, equalityFn) {
1655
1761
  const runtimeBase = useRuntime();
1656
1762
  const runtimeContext = import_react7.default.useContext(RuntimeContext);
@@ -1674,6 +1780,7 @@ function useModule(handle, selectorOrOptions, equalityFn) {
1674
1780
  }
1675
1781
  }
1676
1782
  let runtime;
1783
+ const moduleImplResolveTraceRef = import_react7.default.useRef(void 0);
1677
1784
  if (isModuleImpl(normalizedHandle)) {
1678
1785
  const cache = import_react7.default.useMemo(
1679
1786
  () => getModuleCache(runtimeBase, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion),
@@ -1702,9 +1809,9 @@ function useModule(handle, selectorOrOptions, equalityFn) {
1702
1809
  const key = depsHash ? `${baseKey}:${depsHash}` : baseKey;
1703
1810
  const ownerId = moduleId;
1704
1811
  const baseFactory = import_react7.default.useMemo(
1705
- () => (scope) => import_effect8.Layer.buildWithScope(normalizedHandle.layer, scope).pipe(
1812
+ () => (scope) => import_effect8.Layer.buildWithScope(import_effect8.Layer.fresh(normalizedHandle.layer), scope).pipe(
1706
1813
  import_effect8.Effect.map(
1707
- (context) => import_effect8.Context.get(context, normalizedHandle.module)
1814
+ (context) => import_effect8.ServiceMap.get(context, normalizedHandle.module)
1708
1815
  )
1709
1816
  ),
1710
1817
  [normalizedHandle]
@@ -1714,26 +1821,56 @@ function useModule(handle, selectorOrOptions, equalityFn) {
1714
1821
  return baseFactory;
1715
1822
  }
1716
1823
  return (scope) => baseFactory(scope).pipe(
1717
- import_effect8.Effect.timeoutFail({
1718
- duration: initTimeoutMs,
1719
- onTimeout: () => new Error(`[useModule] Module "${ownerId}" initialization timed out after ${initTimeoutMs}ms`)
1720
- })
1824
+ import_effect8.Effect.timeoutOption(initTimeoutMs),
1825
+ import_effect8.Effect.flatMap(
1826
+ (maybe) => maybe._tag === "Some" ? import_effect8.Effect.succeed(maybe.value) : import_effect8.Effect.die(new Error(`[useModule] Module "${ownerId}" initialization timed out after ${initTimeoutMs}ms`))
1827
+ )
1721
1828
  );
1722
1829
  }, [baseFactory, suspend, initTimeoutMs, ownerId]);
1830
+ const moduleResolveStartedAt = performance.now();
1723
1831
  const moduleRuntime = suspend ? cache.read(key, factory, gcTime, ownerId, {
1724
1832
  entrypoint: "react.useModule",
1725
1833
  policyMode: runtimeContext.policy.mode,
1726
- yield: runtimeContext.policy.yield
1834
+ yield: runtimeContext.policy.yield,
1835
+ optimisticSyncBudgetMs: runtimeContext.policy.syncBudgetMs
1727
1836
  }) : cache.readSync(key, factory, gcTime, ownerId, {
1728
1837
  entrypoint: "react.useModule",
1729
1838
  policyMode: runtimeContext.policy.mode,
1730
1839
  warnSyncBlockingThresholdMs: 5
1731
1840
  });
1841
+ moduleImplResolveTraceRef.current = {
1842
+ moduleId,
1843
+ cacheMode: suspend ? "suspend" : "sync",
1844
+ durationMs: Math.round((performance.now() - moduleResolveStartedAt) * 100) / 100
1845
+ };
1732
1846
  import_react7.default.useEffect(() => cache.retain(key), [cache, key]);
1733
1847
  runtime = moduleRuntime;
1734
1848
  } else {
1735
1849
  runtime = useModuleRuntime(normalizedHandle);
1736
1850
  }
1851
+ import_react7.default.useEffect(() => {
1852
+ if (!isModuleImpl(normalizedHandle)) {
1853
+ return;
1854
+ }
1855
+ const diagnosticsLevel = readRuntimeDiagnosticsLevel(runtimeBase);
1856
+ if (diagnosticsLevel === "off") {
1857
+ return;
1858
+ }
1859
+ const trace = moduleImplResolveTraceRef.current;
1860
+ if (!trace) {
1861
+ return;
1862
+ }
1863
+ const effect = Logix9.Debug.record({
1864
+ type: "trace:react.moduleImpl.resolve",
1865
+ moduleId: trace.moduleId,
1866
+ instanceId: runtime.instanceId,
1867
+ data: {
1868
+ cacheMode: trace.cacheMode,
1869
+ durationMs: trace.durationMs
1870
+ }
1871
+ });
1872
+ emitRuntimeDebugEventBestEffort(runtimeBase, effect);
1873
+ }, [runtimeBase, runtime, normalizedHandle]);
1737
1874
  import_react7.default.useEffect(() => {
1738
1875
  if (!isModuleImpl(normalizedHandle)) {
1739
1876
  return;
@@ -1743,22 +1880,22 @@ function useModule(handle, selectorOrOptions, equalityFn) {
1743
1880
  if (!label) {
1744
1881
  return;
1745
1882
  }
1746
- const effect = Logix7.Debug.record({
1883
+ const effect = Logix9.Debug.record({
1747
1884
  type: "trace:instanceLabel",
1748
1885
  moduleId: normalizedHandle.module.id,
1749
1886
  instanceId: runtime.instanceId,
1750
1887
  data: { label }
1751
1888
  });
1752
- runtimeBase.runFork(effect);
1889
+ emitRuntimeDebugEventBestEffort(runtimeBase, effect);
1753
1890
  }, [runtimeBase, runtime, normalizedHandle, options]);
1754
1891
  import_react7.default.useEffect(() => {
1755
- if (!(0, import_Env.isDevEnv)() && !Logix7.Debug.isDevtoolsEnabled()) {
1892
+ if (!(0, import_Env.isDevEnv)() && !Logix9.Debug.isDevtoolsEnabled()) {
1756
1893
  return;
1757
1894
  }
1758
1895
  if (!runtime.instanceId) {
1759
1896
  return;
1760
1897
  }
1761
- const effect = Logix7.Debug.record({
1898
+ const effect = Logix9.Debug.record({
1762
1899
  type: "trace:react-render",
1763
1900
  moduleId: runtime.moduleId,
1764
1901
  instanceId: runtime.instanceId,
@@ -1768,7 +1905,7 @@ function useModule(handle, selectorOrOptions, equalityFn) {
1768
1905
  }
1769
1906
  });
1770
1907
  runtimeBase.runFork(effect);
1771
- }, [runtimeBase, runtime]);
1908
+ });
1772
1909
  if (selector) {
1773
1910
  if (isModuleImpl(normalizedHandle)) {
1774
1911
  return useSelector(runtime, selector, equalityFn);
@@ -1855,7 +1992,7 @@ function useModule(handle, selectorOrOptions, equalityFn) {
1855
1992
 
1856
1993
  // src/internal/hooks/useLocalModule.ts
1857
1994
  var import_react8 = __toESM(require("react"), 1);
1858
- var Logix8 = __toESM(require("@logixjs/core"), 1);
1995
+ var Logix10 = __toESM(require("@logixjs/core"), 1);
1859
1996
  var import_effect9 = require("effect");
1860
1997
  function isModuleTag(source) {
1861
1998
  if (!source || typeof source !== "object" && typeof source !== "function") {
@@ -1876,7 +2013,7 @@ function useLocalModule(source, second) {
1876
2013
  );
1877
2014
  const componentId = useStableId();
1878
2015
  const moduleTag = import_react8.default.useMemo(() => {
1879
- if (Logix8.Module.is(source)) {
2016
+ if (Logix10.Module.is(source)) {
1880
2017
  return source.tag;
1881
2018
  }
1882
2019
  if (isModuleTag(source)) {
@@ -1885,7 +2022,7 @@ function useLocalModule(source, second) {
1885
2022
  return null;
1886
2023
  }, [source]);
1887
2024
  const def = import_react8.default.useMemo(() => {
1888
- if (Logix8.Module.is(source) || isModuleTag(source)) {
2025
+ if (Logix10.Module.is(source) || isModuleTag(source)) {
1889
2026
  return source;
1890
2027
  }
1891
2028
  return void 0;
@@ -1913,7 +2050,7 @@ function useLocalModule(source, second) {
1913
2050
  return createModuleTagFactory(moduleTag, moduleOptions);
1914
2051
  }
1915
2052
  const factoryFn = source;
1916
- return (scope) => factoryFn().pipe(import_effect9.Scope.extend(scope));
2053
+ return (scope) => import_effect9.Scope.provide(scope)(factoryFn());
1917
2054
  }, [isModule2, moduleTag, source, moduleOptions]);
1918
2055
  const moduleRuntime = cache.readSync(key, factory, void 0, ownerId, {
1919
2056
  entrypoint: "react.useLocalModule",
@@ -1975,7 +2112,7 @@ function createModuleTagFactory(module2, options) {
1975
2112
  const logics = options.logics ?? [];
1976
2113
  return (scope) => import_effect9.Layer.buildWithScope(module2.live(options.initial, ...logics), scope).pipe(
1977
2114
  import_effect9.Effect.map((context) => {
1978
- const runtime = import_effect9.Context.get(context, module2);
2115
+ const runtime = import_effect9.ServiceMap.get(context, module2);
1979
2116
  return runtime;
1980
2117
  })
1981
2118
  );
@@ -1988,7 +2125,7 @@ function useLayerModule(module2, layer, deps = []) {
1988
2125
  const factory = import_react9.default.useCallback(
1989
2126
  () => import_effect10.Layer.build(layer).pipe(
1990
2127
  import_effect10.Effect.scoped,
1991
- import_effect10.Effect.map((context) => import_effect10.Context.get(context, module2))
2128
+ import_effect10.Effect.map((context) => import_effect10.ServiceMap.get(context, module2))
1992
2129
  ),
1993
2130
  // layer/module are typically constants; deps lets callers opt into rebuilding when needed.
1994
2131
  [layer, module2]
@@ -2046,7 +2183,7 @@ function useImportedModule(parent, module2) {
2046
2183
  // src/internal/hooks/useProcesses.ts
2047
2184
  var import_react13 = __toESM(require("react"), 1);
2048
2185
  var import_effect11 = require("effect");
2049
- var Logix9 = __toESM(require("@logixjs/core"), 1);
2186
+ var Logix11 = __toESM(require("@logixjs/core"), 1);
2050
2187
  var ProcessSubtreeRegistry = class {
2051
2188
  constructor(runtime) {
2052
2189
  this.runtime = runtime;
@@ -2112,7 +2249,7 @@ var getRegistry = (runtime) => {
2112
2249
  var stableProcessSignature = (processes) => {
2113
2250
  const ids = [];
2114
2251
  for (let i = 0; i < processes.length; i++) {
2115
- const def = Logix9.Process.getDefinition(processes[i]);
2252
+ const def = Logix11.Process.getDefinition(processes[i]);
2116
2253
  ids.push(def?.processId ?? `legacy#${i}`);
2117
2254
  }
2118
2255
  return ids.join("|");
@@ -2157,7 +2294,7 @@ function useProcesses(processes, options) {
2157
2294
  install: (scope) => {
2158
2295
  const program = import_effect11.Effect.forEach(
2159
2296
  processes,
2160
- (process) => Logix9.InternalContracts.installProcess(process, {
2297
+ (process) => Logix11.InternalContracts.installProcess(process, {
2161
2298
  scope: { type: "uiSubtree", subtreeId },
2162
2299
  enabled: true,
2163
2300
  installedAt: "uiSubtree",
@@ -2169,7 +2306,7 @@ function useProcesses(processes, options) {
2169
2306
  }
2170
2307
  return import_effect11.Effect.forkScoped(process).pipe(import_effect11.Effect.asVoid);
2171
2308
  }),
2172
- import_effect11.Effect.catchAll(() => import_effect11.Effect.forkScoped(process).pipe(import_effect11.Effect.asVoid))
2309
+ import_effect11.Effect.catch(() => import_effect11.Effect.forkScoped(process).pipe(import_effect11.Effect.asVoid))
2173
2310
  ),
2174
2311
  { discard: true }
2175
2312
  ).pipe(import_effect11.Effect.provideService(import_effect11.Scope.Scope, scope));