@logixjs/react 0.1.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 (42) hide show
  1. package/README.md +64 -0
  2. package/dist/Hooks.cjs +2194 -0
  3. package/dist/Hooks.d.cts +77 -0
  4. package/dist/Hooks.d.ts +77 -0
  5. package/dist/Hooks.js +27 -0
  6. package/dist/ModuleRef-wZSQ3Wwo.d.cts +73 -0
  7. package/dist/ModuleRef-wZSQ3Wwo.d.ts +73 -0
  8. package/dist/ModuleScope.cjs +2695 -0
  9. package/dist/ModuleScope.d.cts +62 -0
  10. package/dist/ModuleScope.d.ts +62 -0
  11. package/dist/ModuleScope.js +9 -0
  12. package/dist/Platform.cjs +60 -0
  13. package/dist/Platform.d.cts +6 -0
  14. package/dist/Platform.d.ts +6 -0
  15. package/dist/Platform.js +6 -0
  16. package/dist/ReactPlatform.cjs +2813 -0
  17. package/dist/ReactPlatform.d.cts +40 -0
  18. package/dist/ReactPlatform.d.ts +40 -0
  19. package/dist/ReactPlatform.js +11 -0
  20. package/dist/RuntimeProvider.cjs +1618 -0
  21. package/dist/RuntimeProvider.d.cts +66 -0
  22. package/dist/RuntimeProvider.d.ts +66 -0
  23. package/dist/RuntimeProvider.js +8 -0
  24. package/dist/chunk-2WFULYPJ.js +856 -0
  25. package/dist/chunk-4G7H66OY.js +54 -0
  26. package/dist/chunk-G5MRIFKK.js +95 -0
  27. package/dist/chunk-JXAJTWSZ.js +773 -0
  28. package/dist/chunk-PYWHL7TA.js +351 -0
  29. package/dist/chunk-UFFCJGSZ.js +981 -0
  30. package/dist/chunk-VFWWMK67.js +0 -0
  31. package/dist/chunk-ZANGOPUQ.js +34 -0
  32. package/dist/global.d.cjs +1 -0
  33. package/dist/global.d.d.cts +9 -0
  34. package/dist/global.d.d.ts +9 -0
  35. package/dist/global.d.js +0 -0
  36. package/dist/index.cjs +3118 -0
  37. package/dist/index.d.cts +10 -0
  38. package/dist/index.d.ts +10 -0
  39. package/dist/index.js +44 -0
  40. package/dist/useDispatch-BnzYVkRE.d.ts +81 -0
  41. package/dist/useDispatch-CnO5-66H.d.cts +81 -0
  42. package/package.json +58 -0
package/dist/Hooks.cjs ADDED
@@ -0,0 +1,2194 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/Hooks.ts
31
+ var Hooks_exports = {};
32
+ __export(Hooks_exports, {
33
+ shallow: () => shallow,
34
+ useDispatch: () => useDispatch,
35
+ useImportedModule: () => useImportedModule,
36
+ useLayerModule: () => useLayerModule,
37
+ useLocalModule: () => useLocalModule,
38
+ useModule: () => useModule,
39
+ useModuleList: () => useModuleList,
40
+ useProcesses: () => useProcesses,
41
+ useRuntime: () => useRuntime,
42
+ useSelector: () => useSelector
43
+ });
44
+ module.exports = __toCommonJS(Hooks_exports);
45
+
46
+ // src/internal/hooks/useRuntime.ts
47
+ var import_react3 = require("react");
48
+ var import_effect2 = require("effect");
49
+
50
+ // src/internal/provider/ReactContext.ts
51
+ var import_react = require("react");
52
+ var RuntimeContext = (0, import_react.createContext)(null);
53
+
54
+ // src/internal/provider/env.ts
55
+ var import_Env = require("@logixjs/core/Env");
56
+
57
+ // src/internal/provider/runtimeBindings.ts
58
+ var import_react2 = require("react");
59
+ var import_effect = require("effect");
60
+ var Logix = __toESM(require("@logixjs/core"), 1);
61
+ var toErrorString = (error) => error instanceof Error ? error.stack ?? error.message : String(error);
62
+ var debugScopeCloseFailure = (error) => {
63
+ if (!(0, import_Env.isDevEnv)()) return;
64
+ console.debug("[RuntimeProvider] Scope.close failed", toErrorString(error));
65
+ };
66
+ var useLayerBinding = (runtime, layer, enabled, onError) => {
67
+ const activeBindingRef = (0, import_react2.useRef)(null);
68
+ const [state, setState] = (0, import_react2.useState)(() => ({
69
+ binding: null,
70
+ isLoading: enabled && !!layer,
71
+ runtime,
72
+ layer,
73
+ enabled
74
+ }));
75
+ (0, import_react2.useEffect)(() => {
76
+ if (!enabled || !layer) {
77
+ const current2 = activeBindingRef.current;
78
+ if (current2) {
79
+ activeBindingRef.current = null;
80
+ void runtime.runPromise(import_effect.Scope.close(current2.scope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
81
+ }
82
+ setState((prev) => {
83
+ if (prev.binding === null && prev.isLoading === false && prev.layer === void 0 && prev.enabled === enabled) {
84
+ return prev;
85
+ }
86
+ return {
87
+ binding: null,
88
+ isLoading: false,
89
+ runtime: prev.runtime,
90
+ layer: void 0,
91
+ enabled
92
+ };
93
+ });
94
+ return;
95
+ }
96
+ const current = activeBindingRef.current;
97
+ if (current && current.runtime === runtime && current.layer === layer && current.enabled === enabled) {
98
+ setState({
99
+ binding: current,
100
+ isLoading: false,
101
+ runtime,
102
+ layer,
103
+ enabled
104
+ });
105
+ return;
106
+ }
107
+ const previousBinding = current ?? state.binding;
108
+ if ((0, import_Env.isDevEnv)() && previousBinding && previousBinding.layer !== layer && enabled && layer) {
109
+ console.warn(
110
+ "[RuntimeProvider] Rebuilding layer due to a new layer reference. Memoize the Layer in the caller to avoid repeated rebuilds and resource churn."
111
+ );
112
+ }
113
+ if (current) {
114
+ activeBindingRef.current = null;
115
+ void runtime.runPromise(import_effect.Scope.close(current.scope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
116
+ }
117
+ let cancelled = false;
118
+ setState({
119
+ binding: null,
120
+ isLoading: true,
121
+ runtime,
122
+ layer,
123
+ enabled
124
+ });
125
+ const newScope = import_effect.Effect.runSync(import_effect.Scope.make());
126
+ const buildEffect = import_effect.Effect.gen(function* () {
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));
134
+ const debugSinks = yield* applyEnv(
135
+ import_effect.FiberRef.get(Logix.Debug.internal.currentDebugSinks)
136
+ );
137
+ return { context, loggers, logLevel, debugSinks };
138
+ });
139
+ const assignBinding = (result) => {
140
+ if (cancelled) {
141
+ return runtime.runPromise(import_effect.Scope.close(newScope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
142
+ }
143
+ const previous = activeBindingRef.current;
144
+ const newBinding = {
145
+ context: result.context,
146
+ loggers: result.loggers,
147
+ logLevel: result.logLevel,
148
+ debugSinks: result.debugSinks,
149
+ scope: newScope,
150
+ runtime,
151
+ layer,
152
+ enabled
153
+ };
154
+ activeBindingRef.current = newBinding;
155
+ setState({
156
+ binding: newBinding,
157
+ isLoading: false,
158
+ runtime,
159
+ layer,
160
+ enabled
161
+ });
162
+ if (previous) {
163
+ return runtime.runPromise(import_effect.Scope.close(previous.scope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
164
+ }
165
+ return Promise.resolve();
166
+ };
167
+ let builtSync = false;
168
+ try {
169
+ const result = runtime.runSync(buildEffect);
170
+ builtSync = true;
171
+ void assignBinding(result);
172
+ } catch {
173
+ }
174
+ if (!builtSync) {
175
+ void runtime.runPromise(buildEffect).then(assignBinding).catch((error) => {
176
+ if (onError) {
177
+ const cause = import_effect.Cause.die(error);
178
+ runtime.runFork(
179
+ onError(cause, { source: "provider", phase: "provider.layer.build" }).pipe(
180
+ import_effect.Effect.catchAllCause(() => import_effect.Effect.void)
181
+ )
182
+ );
183
+ }
184
+ void runtime.runPromise(import_effect.Scope.close(newScope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
185
+ if (!cancelled) {
186
+ console.error("[RuntimeProvider] Failed to build layer", error);
187
+ setState({
188
+ binding: null,
189
+ isLoading: false,
190
+ runtime,
191
+ layer,
192
+ enabled
193
+ });
194
+ }
195
+ });
196
+ }
197
+ return () => {
198
+ cancelled = true;
199
+ const current2 = activeBindingRef.current;
200
+ if (current2) {
201
+ activeBindingRef.current = null;
202
+ void runtime.runPromise(import_effect.Scope.close(current2.scope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
203
+ return;
204
+ }
205
+ void runtime.runPromise(import_effect.Scope.close(newScope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
206
+ };
207
+ }, [runtime, layer, enabled, onError]);
208
+ const isCurrentBinding = state.binding !== null && state.runtime === runtime && state.layer === layer && state.enabled === enabled && enabled && !!layer;
209
+ return {
210
+ binding: isCurrentBinding ? state.binding : null,
211
+ isLoading: isCurrentBinding ? state.isLoading : enabled && !!layer
212
+ };
213
+ };
214
+ var createRuntimeAdapter = (runtime, contexts, scopes, loggerSets, logLevels, debugSinks) => {
215
+ if (contexts.length === 0 && scopes.length === 0 && loggerSets.length === 0 && logLevels.length === 0 && debugSinks.length === 0) {
216
+ return runtime;
217
+ }
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
+ )
230
+ )
231
+ );
232
+ const applyLoggers = (effect) => {
233
+ const last = loggerSets.length > 0 ? loggerSets[loggerSets.length - 1] : null;
234
+ const logLevel = logLevels.length > 0 ? logLevels[logLevels.length - 1] : null;
235
+ const sinks = debugSinks.length > 0 ? debugSinks[debugSinks.length - 1] : null;
236
+ let result = effect;
237
+ if (last) {
238
+ result = import_effect.Effect.locally(import_effect.FiberRef.currentLoggers, last)(result);
239
+ }
240
+ if (logLevel) {
241
+ result = import_effect.Effect.locally(import_effect.FiberRef.currentLogLevel, logLevel)(result);
242
+ }
243
+ if (sinks && sinks.length > 0) {
244
+ result = import_effect.Effect.locally(
245
+ Logix.Debug.internal.currentDebugSinks,
246
+ sinks
247
+ )(result);
248
+ }
249
+ return result;
250
+ };
251
+ const adapted = {
252
+ ...runtime,
253
+ runFork: (effect, options) => runtime.runFork(applyLoggers(applyContexts(effect)), options),
254
+ runPromise: (effect, options) => runtime.runPromise(applyLoggers(applyContexts(effect)), options),
255
+ runPromiseExit: (effect, options) => runtime.runPromiseExit(applyLoggers(applyContexts(effect)), options),
256
+ runSync: (effect) => runtime.runSync(applyLoggers(applyContexts(effect))),
257
+ runSyncExit: (effect) => runtime.runSyncExit(applyLoggers(applyContexts(effect))),
258
+ runCallback: (effect, options) => runtime.runCallback(applyLoggers(applyContexts(effect)), options)
259
+ };
260
+ return adapted;
261
+ };
262
+
263
+ // src/internal/provider/errors.ts
264
+ var RuntimeProviderNotFoundError = class extends Error {
265
+ constructor(hookName) {
266
+ super(
267
+ `[${hookName}] RuntimeProvider not found.
268
+
269
+ Fix:
270
+ - Wrap your app (or the calling component subtree) with <RuntimeProvider runtime={runtime}>.
271
+ - If using nested providers, ensure an ancestor RuntimeProvider provides \`runtime\`.
272
+ - If you intended to call this hook outside React, use @logixjs/core directly.
273
+ `
274
+ );
275
+ this.name = "RuntimeProviderNotFoundError";
276
+ }
277
+ };
278
+
279
+ // src/internal/hooks/useRuntime.ts
280
+ function useRuntime(options) {
281
+ const context = (0, import_react3.useContext)(RuntimeContext);
282
+ if (!context) {
283
+ throw new RuntimeProviderNotFoundError("useRuntime");
284
+ }
285
+ const mergedLayerCacheRef = (0, import_react3.useRef)(null);
286
+ const mergedLayer = (0, import_react3.useMemo)(() => {
287
+ if (!options) {
288
+ return void 0;
289
+ }
290
+ const { layer, layers } = options;
291
+ const hasLayersArray = Array.isArray(layers) && layers.length > 0;
292
+ if (!layer && !hasLayersArray) {
293
+ return void 0;
294
+ }
295
+ if (hasLayersArray) {
296
+ const all = layer ? [layer, ...layers] : layers;
297
+ const cached = mergedLayerCacheRef.current;
298
+ const shallowEqual = cached && cached.layers.length === all.length && cached.layers.every((item, idx) => item === all[idx]);
299
+ if (shallowEqual) {
300
+ return cached.merged;
301
+ }
302
+ const merged = import_effect2.Layer.mergeAll(...all);
303
+ mergedLayerCacheRef.current = { layers: all, merged };
304
+ return merged;
305
+ }
306
+ return layer;
307
+ }, [options?.layer, options?.layers]);
308
+ const lastLayersRef = (0, import_react3.useRef)(null);
309
+ const shallowEqualLayers = (a, b) => !!a && !!b && a.length === b.length && a.every((item, idx) => item === b[idx]);
310
+ (0, import_react3.useEffect)(() => {
311
+ if (!(0, import_Env.isDevEnv)()) {
312
+ return;
313
+ }
314
+ if (options?.layers && lastLayersRef.current && lastLayersRef.current !== options.layers && !shallowEqualLayers(lastLayersRef.current, options.layers)) {
315
+ console.warn(
316
+ "[RuntimeProvider] useRuntime received a new layers reference. Memoize the layers array with useMemo to avoid rebuilding Layers on every render (performance jitter)."
317
+ );
318
+ }
319
+ lastLayersRef.current = options?.layers ?? null;
320
+ }, [options?.layers]);
321
+ const { binding } = useLayerBinding(context.runtime, mergedLayer, !!mergedLayer);
322
+ return (0, import_react3.useMemo)(() => {
323
+ if (!binding) {
324
+ return context.runtime;
325
+ }
326
+ return createRuntimeAdapter(
327
+ context.runtime,
328
+ [binding.context],
329
+ [binding.scope],
330
+ [binding.loggers],
331
+ [binding.logLevel],
332
+ [binding.debugSinks]
333
+ );
334
+ }, [context.runtime, binding]);
335
+ }
336
+
337
+ // src/internal/hooks/useModule.ts
338
+ var import_react7 = __toESM(require("react"), 1);
339
+ var Logix7 = __toESM(require("@logixjs/core"), 1);
340
+ var import_effect8 = require("effect");
341
+
342
+ // src/internal/hooks/useModuleRuntime.ts
343
+ var import_react4 = require("react");
344
+ var Logix4 = __toESM(require("@logixjs/core"), 1);
345
+ var import_effect5 = require("effect");
346
+
347
+ // src/internal/store/ModuleRef.ts
348
+ var isModuleRef = (value) => typeof value === "object" && value !== null && "runtime" in value && "actions" in value && "dispatch" in value;
349
+ var makeModuleActions = (dispatch) => {
350
+ const cache = /* @__PURE__ */ new Map();
351
+ const api = new Proxy(
352
+ {},
353
+ {
354
+ get: (_target, prop) => {
355
+ if (cache.has(prop)) {
356
+ return cache.get(prop);
357
+ }
358
+ if (prop === "dispatch") {
359
+ cache.set(prop, dispatch);
360
+ return dispatch;
361
+ }
362
+ if (prop === "then" || typeof prop !== "string") {
363
+ return void 0;
364
+ }
365
+ const fn = (...args) => {
366
+ const payload = args[0];
367
+ dispatch({ _tag: prop, payload });
368
+ };
369
+ cache.set(prop, fn);
370
+ return fn;
371
+ }
372
+ }
373
+ );
374
+ return api;
375
+ };
376
+ function makeModuleDispatchers(dispatch, tokens) {
377
+ const cache = /* @__PURE__ */ new Map();
378
+ if (tokens) {
379
+ const out = {};
380
+ for (const [key, token] of Object.entries(tokens)) {
381
+ const fn = Object.assign(
382
+ ((...args) => {
383
+ const action = token(...args);
384
+ dispatch(action);
385
+ return action;
386
+ }),
387
+ token
388
+ );
389
+ out[key] = fn;
390
+ }
391
+ return out;
392
+ }
393
+ const api = new Proxy(
394
+ {},
395
+ {
396
+ get: (_target, prop) => {
397
+ if (cache.has(prop)) {
398
+ return cache.get(prop);
399
+ }
400
+ if (prop === "then" || prop === "dispatch" || typeof prop !== "string") {
401
+ return void 0;
402
+ }
403
+ const fn = (...args) => {
404
+ const payload = args[0];
405
+ const action = { _tag: prop, payload };
406
+ dispatch(action);
407
+ return action;
408
+ };
409
+ cache.set(prop, fn);
410
+ return fn;
411
+ }
412
+ }
413
+ );
414
+ return api;
415
+ }
416
+ var HANDLE_EXTEND = /* @__PURE__ */ Symbol.for("logix.module.handle.extend");
417
+ var isObjectLike = (value) => typeof value === "object" && value !== null || typeof value === "function";
418
+ var applyHandleExtend = (tag, runtime, base) => {
419
+ if (!isObjectLike(tag)) {
420
+ return base;
421
+ }
422
+ const extend = tag[HANDLE_EXTEND];
423
+ if (typeof extend !== "function") {
424
+ return base;
425
+ }
426
+ const next = extend(
427
+ runtime,
428
+ base
429
+ );
430
+ if (!next || typeof next !== "object") {
431
+ return base;
432
+ }
433
+ return { ...base, ...next };
434
+ };
435
+
436
+ // src/internal/store/ModuleCache.ts
437
+ var Logix3 = __toESM(require("@logixjs/core"), 1);
438
+ var import_effect4 = require("effect");
439
+
440
+ // 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
445
+ });
446
+ var PerfCounterActions = {
447
+ inc: import_effect3.Schema.Void
448
+ };
449
+ var PerfListScopeRowSchema = import_effect3.Schema.Struct({
450
+ id: import_effect3.Schema.String,
451
+ warehouseId: import_effect3.Schema.String
452
+ });
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
457
+ });
458
+ var GLOBAL_YIELD_BUDGET_MEMORY_KEY = "__LOGIX_REACT_YIELD_BUDGET_MEMORY__";
459
+ var getGlobalYieldBudgetMemory = () => {
460
+ const root = globalThis;
461
+ const existing = root[GLOBAL_YIELD_BUDGET_MEMORY_KEY];
462
+ if (existing && existing.byRuntime instanceof WeakMap) {
463
+ return existing;
464
+ }
465
+ const created = { byRuntime: /* @__PURE__ */ new WeakMap() };
466
+ root[GLOBAL_YIELD_BUDGET_MEMORY_KEY] = created;
467
+ return created;
468
+ };
469
+ var getStatsMapForRuntime = (runtime) => {
470
+ const global = getGlobalYieldBudgetMemory();
471
+ const cached = global.byRuntime.get(runtime);
472
+ if (cached) return cached;
473
+ const created = /* @__PURE__ */ new Map();
474
+ global.byRuntime.set(runtime, created);
475
+ return created;
476
+ };
477
+ var quantile = (sorted, q) => {
478
+ if (sorted.length === 0) return Number.NaN;
479
+ const clamped = Math.min(1, Math.max(0, q));
480
+ const idx = Math.floor(clamped * (sorted.length - 1));
481
+ return sorted[idx];
482
+ };
483
+ var p95 = (samplesMs) => {
484
+ if (samplesMs.length === 0) return Number.NaN;
485
+ const sorted = samplesMs.slice().sort((a, b) => a - b);
486
+ return quantile(sorted, 0.95);
487
+ };
488
+ var YieldBudgetMemory = {
489
+ shouldYield(args) {
490
+ const budgetMs = args.policy?.onlyWhenOverBudgetMs;
491
+ if (budgetMs === void 0) {
492
+ return { shouldYield: true, reason: "budgetDisabled", p95Ms: void 0 };
493
+ }
494
+ const byKey = getStatsMapForRuntime(args.runtime);
495
+ const stats = byKey.get(args.workloadKey) ?? { seen: false, samplesMs: [] };
496
+ if (!byKey.has(args.workloadKey)) {
497
+ byKey.set(args.workloadKey, stats);
498
+ }
499
+ if (!stats.seen) {
500
+ stats.seen = true;
501
+ return { shouldYield: true, reason: "firstRun", p95Ms: void 0 };
502
+ }
503
+ if (stats.samplesMs.length === 0) {
504
+ return { shouldYield: true, reason: "insufficientSamples", p95Ms: void 0 };
505
+ }
506
+ const p95Ms = p95(stats.samplesMs);
507
+ if (!Number.isFinite(p95Ms)) {
508
+ return { shouldYield: true, reason: "insufficientSamples", p95Ms: void 0 };
509
+ }
510
+ return p95Ms > budgetMs ? { shouldYield: true, reason: "overBudget", p95Ms } : { shouldYield: false, reason: "underBudget", p95Ms };
511
+ },
512
+ record(args) {
513
+ if (!Number.isFinite(args.durationMs) || args.durationMs < 0) return;
514
+ const byKey = getStatsMapForRuntime(args.runtime);
515
+ const stats = byKey.get(args.workloadKey) ?? { seen: true, samplesMs: [] };
516
+ if (!byKey.has(args.workloadKey)) {
517
+ byKey.set(args.workloadKey, stats);
518
+ }
519
+ stats.samplesMs.push(args.durationMs);
520
+ if (stats.samplesMs.length > 20) {
521
+ stats.samplesMs.shift();
522
+ }
523
+ }
524
+ };
525
+
526
+ // src/internal/store/ModuleCache.ts
527
+ var RUNTIME_CACHE = /* @__PURE__ */ new WeakMap();
528
+ var DEFAULT_GC_DELAY_MS = 500;
529
+ var ERROR_GC_DELAY_MS = 500;
530
+ var DEFAULT_RENDER_SYNC_BLOCKING_WARN_THRESHOLD_MS = 5;
531
+ var toErrorString2 = (error) => {
532
+ if (error instanceof Error) {
533
+ return error.stack ?? error.message;
534
+ }
535
+ return String(error);
536
+ };
537
+ var seenBestEffortFailures = /* @__PURE__ */ new Set();
538
+ var debugBestEffortFailure = (label, error) => {
539
+ if (!(0, import_Env.isDevEnv)()) return;
540
+ const message = toErrorString2(error);
541
+ if (message.includes("ManagedRuntime disposed")) {
542
+ return;
543
+ }
544
+ const key = `${label}
545
+ ${message}`;
546
+ if (seenBestEffortFailures.has(key)) return;
547
+ seenBestEffortFailures.add(key);
548
+ console.debug(label, message);
549
+ };
550
+ var causeToUnknown = (cause) => {
551
+ const failure = import_effect4.Option.getOrUndefined(import_effect4.Cause.failureOption(cause));
552
+ if (failure !== void 0) return failure;
553
+ const defect = import_effect4.Option.getOrUndefined(import_effect4.Cause.dieOption(cause));
554
+ if (defect !== void 0) return defect;
555
+ return cause;
556
+ };
557
+ var yieldEffect = (strategy) => {
558
+ switch (strategy) {
559
+ case "none":
560
+ return import_effect4.Effect.void;
561
+ case "microtask":
562
+ return import_effect4.Effect.yieldNow();
563
+ case "macrotask":
564
+ return import_effect4.Effect.promise(
565
+ () => new Promise((resolve) => {
566
+ setTimeout(resolve, 0);
567
+ })
568
+ );
569
+ }
570
+ };
571
+ var decideYieldStrategy = (runtime, workloadKey, policy) => {
572
+ const baseStrategy = policy?.strategy ?? "microtask";
573
+ if (baseStrategy === "none") {
574
+ return { strategy: "none", reason: "disabled" };
575
+ }
576
+ const budgetMs = policy?.onlyWhenOverBudgetMs;
577
+ if (budgetMs === void 0) {
578
+ return { strategy: baseStrategy };
579
+ }
580
+ const decision = YieldBudgetMemory.shouldYield({ runtime, workloadKey, policy });
581
+ return decision.shouldYield ? { strategy: baseStrategy, reason: decision.reason, p95Ms: decision.p95Ms } : { strategy: "none", reason: decision.reason, p95Ms: decision.p95Ms };
582
+ };
583
+ var warnedSyncBlockingKeys = /* @__PURE__ */ new Set();
584
+ var ModuleCache = class {
585
+ constructor(runtime, gcDelayMs = DEFAULT_GC_DELAY_MS) {
586
+ this.runtime = runtime;
587
+ this.gcDelayMs = gcDelayMs;
588
+ this.entries = /* @__PURE__ */ new Map();
589
+ }
590
+ scheduleGC(key, entry) {
591
+ if (entry.gcTimeout) {
592
+ return;
593
+ }
594
+ const delay = entry.gcTime;
595
+ if (!Number.isFinite(delay)) {
596
+ return;
597
+ }
598
+ const timeoutMs = delay <= 0 ? 0 : delay;
599
+ entry.gcTimeout = setTimeout(() => {
600
+ const current = this.entries.get(key);
601
+ if (!current || current !== entry) {
602
+ return;
603
+ }
604
+ current.gcTimeout = void 0;
605
+ if (current.refCount > 0 || current.preloadRefCount > 0) {
606
+ return;
607
+ }
608
+ if (current.status === "pending") {
609
+ this.scheduleGC(key, current);
610
+ return;
611
+ }
612
+ void this.runtime.runPromise(import_effect4.Scope.close(current.scope, import_effect4.Exit.void)).catch((error) => {
613
+ debugBestEffortFailure("[ModuleCache] Scope.close failed", error);
614
+ });
615
+ void this.runtime.runPromise(
616
+ Logix3.Debug.record({
617
+ type: "trace:react.module-instance",
618
+ moduleId: current.ownerId,
619
+ instanceId: current.value?.instanceId,
620
+ data: {
621
+ event: "gc",
622
+ key
623
+ }
624
+ })
625
+ ).catch((error) => {
626
+ debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
627
+ });
628
+ this.entries.delete(key);
629
+ }, timeoutMs);
630
+ }
631
+ read(key, factory, gcTime, ownerId, options) {
632
+ const existing = this.entries.get(key);
633
+ if (existing) {
634
+ if ((0, import_Env.isDevEnv)() && existing.ownerId !== void 0 && ownerId !== void 0 && existing.ownerId !== ownerId) {
635
+ console.error(
636
+ "[ModuleCache.read] resource key ownership mismatch:",
637
+ `key="${key}" previously owned by "${existing.ownerId}",`,
638
+ `but now requested by "${ownerId}".`
639
+ );
640
+ throw new Error(
641
+ `[ModuleCache.read] resource key "${key}" has already been claimed by module "${existing.ownerId}", but is now requested by module "${ownerId}". Within the same ManagedRuntime, a given key must not be shared across different ModuleImpl definitions. Please ensure each ModuleImpl uses a distinct key when sharing ModuleRuntime instances.`
642
+ );
643
+ }
644
+ if (existing.status === "pending") {
645
+ throw existing.promise;
646
+ }
647
+ if (existing.status === "error") {
648
+ throw existing.error;
649
+ }
650
+ return existing.value;
651
+ }
652
+ const scope = import_effect4.Effect.runSync(import_effect4.Scope.make());
653
+ const workloadKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`;
654
+ const yieldDecision = decideYieldStrategy(this.runtime, workloadKey, options?.yield);
655
+ const entry = {
656
+ scope,
657
+ status: "pending",
658
+ // Placeholder; will be replaced immediately with the real Promise.
659
+ promise: Promise.resolve(null),
660
+ refCount: 0,
661
+ preloadRefCount: 0,
662
+ gcTime: gcTime ?? this.gcDelayMs,
663
+ ownerId,
664
+ createdBy: "read",
665
+ workloadKey,
666
+ yieldStrategy: yieldDecision.strategy
667
+ };
668
+ this.scheduleGC(key, entry);
669
+ const startedAt = performance.now();
670
+ const buildEffect = yieldEffect(yieldDecision.strategy).pipe(import_effect4.Effect.zipRight(factory(scope)));
671
+ const fiber = this.runtime.runFork(buildEffect);
672
+ 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;
675
+ throw causeToUnknown(exit.cause);
676
+ });
677
+ promise.then((value) => {
678
+ entry.status = "success";
679
+ entry.value = value;
680
+ const durationMs = performance.now() - startedAt;
681
+ YieldBudgetMemory.record({ runtime: this.runtime, workloadKey, durationMs });
682
+ if ((0, import_Env.isDevEnv)() || Logix3.Debug.isDevtoolsEnabled()) {
683
+ void this.runtime.runPromise(
684
+ Logix3.Debug.record({
685
+ type: "trace:react.module.init",
686
+ moduleId: ownerId,
687
+ instanceId: value.instanceId,
688
+ data: {
689
+ mode: "suspend",
690
+ key,
691
+ durationMs: Math.round(durationMs * 100) / 100,
692
+ yieldStrategy: yieldDecision.strategy,
693
+ yieldReason: yieldDecision.reason,
694
+ yieldP95Ms: yieldDecision.p95Ms
695
+ }
696
+ })
697
+ ).catch((error) => {
698
+ debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
699
+ });
700
+ void this.runtime.runPromise(
701
+ Logix3.Debug.record({
702
+ type: "trace:react.module-instance",
703
+ moduleId: ownerId,
704
+ instanceId: value.instanceId,
705
+ data: {
706
+ event: "attach",
707
+ key,
708
+ mode: "suspend",
709
+ gcTime: entry.gcTime
710
+ }
711
+ })
712
+ ).catch((error) => {
713
+ debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
714
+ });
715
+ }
716
+ return value;
717
+ }).catch((error) => {
718
+ entry.status = "error";
719
+ entry.error = error;
720
+ entry.gcTime = ERROR_GC_DELAY_MS;
721
+ if (entry.gcTimeout) {
722
+ clearTimeout(entry.gcTimeout);
723
+ entry.gcTimeout = void 0;
724
+ }
725
+ this.scheduleGC(key, entry);
726
+ YieldBudgetMemory.record({
727
+ runtime: this.runtime,
728
+ workloadKey,
729
+ durationMs: performance.now() - startedAt
730
+ });
731
+ void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
732
+ debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
733
+ });
734
+ throw error;
735
+ });
736
+ this.entries.set(key, entry);
737
+ entry.promise = promise;
738
+ throw promise;
739
+ }
740
+ readSync(key, factory, gcTime, ownerId, options) {
741
+ const existing = this.entries.get(key);
742
+ if (existing) {
743
+ if ((0, import_Env.isDevEnv)() && existing.ownerId !== void 0 && ownerId !== void 0 && existing.ownerId !== ownerId) {
744
+ console.error(
745
+ "[ModuleCache.readSync] resource key ownership mismatch:",
746
+ `key="${key}" previously owned by "${existing.ownerId}",`,
747
+ `but now requested by "${ownerId}".`
748
+ );
749
+ throw new Error(
750
+ `[ModuleCache.readSync] resource key "${key}" has already been claimed by module "${existing.ownerId}", but is now requested by module "${ownerId}". Within the same ManagedRuntime, a given key must not be shared across different ModuleImpl definitions. Please ensure each ModuleImpl uses a distinct key when sharing ModuleRuntime instances.`
751
+ );
752
+ }
753
+ if (existing.status === "error") {
754
+ throw existing.error;
755
+ }
756
+ if (existing.status === "pending") {
757
+ throw new Error(
758
+ `[ModuleCache.readSync] encountered pending entry for key="${key}". This usually indicates that the same resource key is being used by both suspend:true (async) and sync consumers. Please either give different keys to async/sync callers, or stick to a single access mode for this resource.`
759
+ );
760
+ }
761
+ return existing.value;
762
+ }
763
+ const scope = this.runtime.runSync(import_effect4.Scope.make());
764
+ const startedAt = performance.now();
765
+ try {
766
+ const value = this.runtime.runSync(factory(scope));
767
+ const durationMs = performance.now() - startedAt;
768
+ const entry = {
769
+ scope,
770
+ status: "success",
771
+ promise: Promise.resolve(value),
772
+ value,
773
+ refCount: 0,
774
+ preloadRefCount: 0,
775
+ gcTime: gcTime ?? this.gcDelayMs,
776
+ ownerId,
777
+ createdBy: "read",
778
+ workloadKey: `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`,
779
+ yieldStrategy: "none"
780
+ };
781
+ this.scheduleGC(key, entry);
782
+ this.entries.set(key, entry);
783
+ if ((0, import_Env.isDevEnv)()) {
784
+ const threshold = options?.warnSyncBlockingThresholdMs ?? DEFAULT_RENDER_SYNC_BLOCKING_WARN_THRESHOLD_MS;
785
+ if (threshold > 0 && durationMs > threshold) {
786
+ const dedupeKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}::${key}`;
787
+ if (!warnedSyncBlockingKeys.has(dedupeKey)) {
788
+ warnedSyncBlockingKeys.add(dedupeKey);
789
+ const hint = options?.policyMode === "defer" ? 'Fix: \u5F53\u524D policy.mode="defer"\uFF1A\u8BF7\u68C0\u67E5\u8BE5\u6A21\u5757\u662F\u5426\u5728 policy.preload \u5217\u8868\u4E2D\uFF1B\u672A\u9884\u52A0\u8F7D\u7684\u6A21\u5757\u4ECD\u53EF\u80FD\u89E6\u53D1\u4E8C\u6B21 fallback \u6216\u540C\u6B65\u91CD\u6D3B\u3002' : 'Fix: \u5EFA\u8BAE\u5207\u6362\u5230 policy.mode="suspend"\uFF08\u9ED8\u8BA4\uFF09\uFF0C\u5E76\u63D0\u4F9B RuntimeProvider.fallback\uFF1B\u5FC5\u8981\u65F6\u542F\u7528 yield \u7B56\u7565\u3002';
790
+ const example = options?.policyMode === "defer" ? 'Example: <RuntimeProvider policy={{ mode: "defer", preload: [MyImpl] }} fallback={<Loading />}>\u2026</RuntimeProvider>' : 'Example: <RuntimeProvider policy={{ mode: "suspend" }} fallback={<Loading />}>\u2026</RuntimeProvider>';
791
+ const docs = "Docs: apps/docs/content/docs/guide/essentials/react-integration.md";
792
+ console.warn(
793
+ "[Logix][React] Render-phase sync blocking detected",
794
+ `(${Math.round(durationMs * 100) / 100}ms > ${threshold}ms)`,
795
+ "\n",
796
+ `entrypoint=${options?.entrypoint ?? "unknown"}`,
797
+ "\n",
798
+ `ownerId=${ownerId ?? "unknown"}`,
799
+ "\n",
800
+ `key=${key}`,
801
+ "\n",
802
+ hint,
803
+ "\n",
804
+ example,
805
+ "\n",
806
+ docs
807
+ );
808
+ }
809
+ }
810
+ }
811
+ if ((0, import_Env.isDevEnv)() || Logix3.Debug.isDevtoolsEnabled()) {
812
+ void this.runtime.runPromise(
813
+ Logix3.Debug.record({
814
+ type: "trace:react.module.init",
815
+ moduleId: ownerId,
816
+ instanceId: value.instanceId,
817
+ data: {
818
+ mode: "sync",
819
+ key,
820
+ durationMs: Math.round(durationMs * 100) / 100,
821
+ yieldStrategy: "none"
822
+ }
823
+ })
824
+ ).catch((error) => {
825
+ debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
826
+ });
827
+ void this.runtime.runPromise(
828
+ Logix3.Debug.record({
829
+ type: "trace:react.module-instance",
830
+ moduleId: ownerId,
831
+ instanceId: value.instanceId,
832
+ data: {
833
+ event: "attach",
834
+ key,
835
+ mode: "sync",
836
+ gcTime: entry.gcTime
837
+ }
838
+ })
839
+ ).catch((error) => {
840
+ debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
841
+ });
842
+ }
843
+ return value;
844
+ } catch (error) {
845
+ void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
846
+ debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
847
+ });
848
+ const entry = {
849
+ scope,
850
+ status: "error",
851
+ promise: Promise.reject(error),
852
+ error,
853
+ refCount: 0,
854
+ preloadRefCount: 0,
855
+ gcTime: ERROR_GC_DELAY_MS,
856
+ ownerId,
857
+ createdBy: "read",
858
+ workloadKey: `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`,
859
+ yieldStrategy: "none"
860
+ };
861
+ this.scheduleGC(key, entry);
862
+ this.entries.set(key, entry);
863
+ throw error;
864
+ }
865
+ }
866
+ preload(key, factory, options) {
867
+ const existing = this.entries.get(key);
868
+ if (existing) {
869
+ if (existing.status === "success") {
870
+ existing.preloadRefCount += 1;
871
+ return {
872
+ promise: Promise.resolve(existing.value),
873
+ cancel: () => {
874
+ this.cancelPreload(key, existing);
875
+ }
876
+ };
877
+ }
878
+ if (existing.status === "error") {
879
+ return { promise: Promise.reject(existing.error), cancel: () => {
880
+ } };
881
+ }
882
+ existing.preloadRefCount += 1;
883
+ return {
884
+ promise: existing.promise,
885
+ cancel: () => {
886
+ this.cancelPreload(key, existing);
887
+ }
888
+ };
889
+ }
890
+ const scope = import_effect4.Effect.runSync(import_effect4.Scope.make());
891
+ const ownerId = options?.ownerId;
892
+ const gcTime = options?.gcTime ?? this.gcDelayMs;
893
+ const workloadKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`;
894
+ const yieldDecision = decideYieldStrategy(this.runtime, workloadKey, options?.yield);
895
+ const entry = {
896
+ scope,
897
+ status: "pending",
898
+ promise: Promise.resolve(null),
899
+ refCount: 0,
900
+ preloadRefCount: 1,
901
+ gcTime,
902
+ ownerId,
903
+ createdBy: "preload",
904
+ workloadKey,
905
+ yieldStrategy: yieldDecision.strategy
906
+ };
907
+ this.scheduleGC(key, entry);
908
+ this.entries.set(key, entry);
909
+ const startedAt = performance.now();
910
+ const buildEffect = yieldEffect(yieldDecision.strategy).pipe(import_effect4.Effect.zipRight(factory(scope)));
911
+ const fiber = this.runtime.runFork(buildEffect);
912
+ 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;
915
+ throw causeToUnknown(exit.cause);
916
+ });
917
+ entry.promise = promise;
918
+ void promise.then((value) => {
919
+ entry.status = "success";
920
+ entry.value = value;
921
+ YieldBudgetMemory.record({
922
+ runtime: this.runtime,
923
+ workloadKey,
924
+ durationMs: performance.now() - startedAt
925
+ });
926
+ }).catch((error) => {
927
+ entry.status = "error";
928
+ entry.error = error;
929
+ entry.gcTime = ERROR_GC_DELAY_MS;
930
+ if (entry.gcTimeout) {
931
+ clearTimeout(entry.gcTimeout);
932
+ entry.gcTimeout = void 0;
933
+ }
934
+ this.scheduleGC(key, entry);
935
+ YieldBudgetMemory.record({
936
+ runtime: this.runtime,
937
+ workloadKey,
938
+ durationMs: performance.now() - startedAt
939
+ });
940
+ void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
941
+ debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
942
+ });
943
+ });
944
+ return {
945
+ promise,
946
+ cancel: () => {
947
+ this.cancelPreload(key, entry);
948
+ }
949
+ };
950
+ }
951
+ cancelPreload(key, entry) {
952
+ const current = this.entries.get(key);
953
+ if (!current || current !== entry) {
954
+ return;
955
+ }
956
+ entry.preloadRefCount = Math.max(0, entry.preloadRefCount - 1);
957
+ if (entry.preloadRefCount > 0) {
958
+ return;
959
+ }
960
+ if (entry.refCount > 0) {
961
+ return;
962
+ }
963
+ if (entry.status === "pending") {
964
+ if (entry.createdBy !== "preload") {
965
+ this.scheduleGC(key, entry);
966
+ return;
967
+ }
968
+ const running = entry.fiber;
969
+ entry.fiber = void 0;
970
+ this.entries.delete(key);
971
+ if (running) {
972
+ this.runtime.runFork(import_effect4.Fiber.interrupt(running));
973
+ }
974
+ void this.runtime.runPromise(import_effect4.Scope.close(entry.scope, import_effect4.Exit.void)).catch((closeError) => {
975
+ debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
976
+ });
977
+ return;
978
+ }
979
+ if (entry.gcTimeout) {
980
+ clearTimeout(entry.gcTimeout);
981
+ entry.gcTimeout = void 0;
982
+ }
983
+ this.scheduleGC(key, entry);
984
+ }
985
+ /**
986
+ * Declares ownership of a resource after component commit.
987
+ * The returned function releases the reference during cleanup.
988
+ */
989
+ retain(key) {
990
+ const entry = this.entries.get(key);
991
+ if (!entry) {
992
+ return () => {
993
+ };
994
+ }
995
+ entry.refCount += 1;
996
+ if (entry.gcTimeout) {
997
+ clearTimeout(entry.gcTimeout);
998
+ entry.gcTimeout = void 0;
999
+ }
1000
+ return () => {
1001
+ this.release(key);
1002
+ };
1003
+ }
1004
+ release(key) {
1005
+ const entry = this.entries.get(key);
1006
+ if (!entry) {
1007
+ return;
1008
+ }
1009
+ entry.refCount -= 1;
1010
+ if (entry.refCount > 0) {
1011
+ return;
1012
+ }
1013
+ this.scheduleGC(key, entry);
1014
+ }
1015
+ dispose() {
1016
+ for (const [key, entry] of this.entries) {
1017
+ if (entry.gcTimeout) {
1018
+ clearTimeout(entry.gcTimeout);
1019
+ }
1020
+ void this.runtime.runPromise(import_effect4.Scope.close(entry.scope, import_effect4.Exit.void)).catch((error) => {
1021
+ debugBestEffortFailure("[ModuleCache] Scope.close failed", error);
1022
+ });
1023
+ this.entries.delete(key);
1024
+ }
1025
+ }
1026
+ };
1027
+ var getModuleCache = (runtime, config, version) => {
1028
+ const cached = RUNTIME_CACHE.get(runtime);
1029
+ if (cached && cached.version === version) {
1030
+ return cached.cache;
1031
+ }
1032
+ if (cached) {
1033
+ cached.cache.dispose();
1034
+ }
1035
+ const cache = new ModuleCache(runtime, config.gcTime);
1036
+ RUNTIME_CACHE.set(runtime, { version, cache });
1037
+ return cache;
1038
+ };
1039
+ var hashOf = (value) => {
1040
+ if (value === null) {
1041
+ return "null";
1042
+ }
1043
+ const type = typeof value;
1044
+ if (type === "string") {
1045
+ return `s:${value}`;
1046
+ }
1047
+ if (type === "number") {
1048
+ return `n:${value}`;
1049
+ }
1050
+ if (type === "boolean") {
1051
+ return `b:${value}`;
1052
+ }
1053
+ return `${type}:${Object.prototype.toString.call(value)}`;
1054
+ };
1055
+ var stableHash = (deps) => {
1056
+ if ((0, import_Env.isDevEnv)()) {
1057
+ const hasNonPrimitive = deps.some((value) => {
1058
+ if (value === null) return false;
1059
+ const type = typeof value;
1060
+ return type === "object" || type === "function";
1061
+ });
1062
+ if (hasNonPrimitive) {
1063
+ console.warn(
1064
+ "[ModuleCache] deps contains non-primitive values. stableHash() only distinguishes primitives (string/number/boolean/null/undefined); object/function entries may not trigger expected cache updates. Consider passing explicit primitive deps or controlling invalidation via `key`."
1065
+ );
1066
+ }
1067
+ }
1068
+ return deps.map(hashOf).join("|");
1069
+ };
1070
+
1071
+ // src/internal/hooks/useModuleRuntime.ts
1072
+ var isModuleRuntime = (value) => typeof value === "object" && value !== null && "dispatch" in value && "getState" in value;
1073
+ function useModuleRuntime(handle) {
1074
+ const runtime = useRuntime();
1075
+ const runtimeContext = (0, import_react4.useContext)(RuntimeContext);
1076
+ if (!runtimeContext) {
1077
+ throw new RuntimeProviderNotFoundError("useModuleRuntime");
1078
+ }
1079
+ const cache = (0, import_react4.useMemo)(
1080
+ () => getModuleCache(runtimeContext.runtime, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion),
1081
+ [runtimeContext.runtime, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion]
1082
+ );
1083
+ const isTagHandle = !isModuleRef(handle) && !isModuleRuntime(handle);
1084
+ const resolved = (0, import_react4.useMemo)(() => {
1085
+ if (isModuleRef(handle)) {
1086
+ return handle.runtime;
1087
+ }
1088
+ if (isModuleRuntime(handle)) {
1089
+ return handle;
1090
+ }
1091
+ const tag = handle;
1092
+ const tokenId = tag.id ?? "ModuleTag";
1093
+ const preloadKey = runtimeContext.policy.preload?.keysByTagId.get(tokenId);
1094
+ const key = preloadKey ?? `tag:${tokenId}`;
1095
+ 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, {
1098
+ entrypoint: "react.useModuleRuntime",
1099
+ policyMode: runtimeContext.policy.mode,
1100
+ yield: runtimeContext.policy.yield
1101
+ }) : cache.readSync(key, factory, void 0, tokenId, {
1102
+ entrypoint: "react.useModuleRuntime",
1103
+ policyMode: runtimeContext.policy.mode,
1104
+ warnSyncBlockingThresholdMs: 5
1105
+ });
1106
+ }, [cache, runtimeContext.policy, handle]);
1107
+ (0, import_react4.useEffect)(() => {
1108
+ if (!isTagHandle) {
1109
+ return;
1110
+ }
1111
+ if (!(0, import_Env.isDevEnv)() && !Logix4.Debug.isDevtoolsEnabled()) {
1112
+ return;
1113
+ }
1114
+ const tokenId = handle?.id ?? "ModuleTag";
1115
+ const effect = Logix4.Debug.record({
1116
+ type: "trace:react.moduleTag.resolve",
1117
+ moduleId: resolved.moduleId,
1118
+ instanceId: resolved.instanceId,
1119
+ data: {
1120
+ mode: runtimeContext.policy.moduleTagMode,
1121
+ tokenId,
1122
+ yieldStrategy: runtimeContext.policy.yield.strategy
1123
+ }
1124
+ });
1125
+ runtime.runFork(effect);
1126
+ }, [runtime, runtimeContext.policy, resolved, handle, isTagHandle]);
1127
+ return resolved;
1128
+ }
1129
+
1130
+ // src/internal/hooks/useSelector.ts
1131
+ var import_react5 = require("react");
1132
+ var import_with_selector = require("use-sync-external-store/shim/with-selector");
1133
+ var Logix5 = __toESM(require("@logixjs/core"), 1);
1134
+
1135
+ // src/internal/store/ModuleRuntimeExternalStore.ts
1136
+ var import_effect6 = require("effect");
1137
+ var storesByRuntime = /* @__PURE__ */ new WeakMap();
1138
+ var getStoreMapForRuntime = (runtime) => {
1139
+ const cached = storesByRuntime.get(runtime);
1140
+ if (cached) return cached;
1141
+ const next = /* @__PURE__ */ new WeakMap();
1142
+ storesByRuntime.set(runtime, next);
1143
+ return next;
1144
+ };
1145
+ var getModuleRuntimeExternalStore = (runtime, moduleRuntime, options) => {
1146
+ const byModule = getStoreMapForRuntime(runtime);
1147
+ const cached = byModule.get(moduleRuntime);
1148
+ if (cached) {
1149
+ return cached;
1150
+ }
1151
+ let currentState;
1152
+ const listeners = /* @__PURE__ */ new Set();
1153
+ const lowPriorityDelayMs = options?.lowPriorityDelayMs ?? 16;
1154
+ const lowPriorityMaxDelayMs = options?.lowPriorityMaxDelayMs ?? 50;
1155
+ let notifyScheduled = false;
1156
+ let notifyScheduledLow = false;
1157
+ let lowTimeoutId;
1158
+ let lowMaxTimeoutId;
1159
+ let lowRafId;
1160
+ const cancelLow = () => {
1161
+ if (!notifyScheduledLow) return;
1162
+ 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
+ }
1176
+ };
1177
+ const flushNotify = () => {
1178
+ notifyScheduled = false;
1179
+ cancelLow();
1180
+ for (const listener of listeners) {
1181
+ listener();
1182
+ }
1183
+ };
1184
+ const scheduleNotify = (priority) => {
1185
+ if (priority === "low") {
1186
+ if (notifyScheduled) return;
1187
+ if (notifyScheduledLow) return;
1188
+ notifyScheduledLow = true;
1189
+ const flush = () => {
1190
+ if (!notifyScheduledLow) return;
1191
+ flushNotify();
1192
+ };
1193
+ const raf = globalThis.requestAnimationFrame;
1194
+ if (raf) {
1195
+ lowRafId = raf(flush);
1196
+ } else {
1197
+ lowTimeoutId = setTimeout(flush, lowPriorityDelayMs);
1198
+ }
1199
+ lowMaxTimeoutId = setTimeout(flush, lowPriorityMaxDelayMs);
1200
+ return;
1201
+ }
1202
+ cancelLow();
1203
+ if (notifyScheduled) return;
1204
+ notifyScheduled = true;
1205
+ queueMicrotask(flushNotify);
1206
+ };
1207
+ let fiber;
1208
+ 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
+ );
1219
+ };
1220
+ const refreshSnapshotIfStale = () => {
1221
+ if (currentState === void 0) {
1222
+ return;
1223
+ }
1224
+ try {
1225
+ const latest = runtime.runSync(moduleRuntime.getState);
1226
+ if (currentState === void 0 || !Object.is(currentState, latest)) {
1227
+ currentState = latest;
1228
+ scheduleNotify("normal");
1229
+ }
1230
+ } catch {
1231
+ }
1232
+ };
1233
+ const getSnapshot = () => {
1234
+ if (currentState !== void 0) return currentState;
1235
+ currentState = runtime.runSync(moduleRuntime.getState);
1236
+ return currentState;
1237
+ };
1238
+ const subscribe = (listener) => {
1239
+ listeners.add(listener);
1240
+ ensureSubscription();
1241
+ refreshSnapshotIfStale();
1242
+ return () => {
1243
+ listeners.delete(listener);
1244
+ 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));
1250
+ };
1251
+ };
1252
+ const store = { getSnapshot, subscribe };
1253
+ byModule.set(moduleRuntime, store);
1254
+ return store;
1255
+ };
1256
+
1257
+ // src/internal/store/ModuleRuntimeSelectorExternalStore.ts
1258
+ var import_effect7 = require("effect");
1259
+
1260
+ // src/internal/hooks/shallow.ts
1261
+ var hasObjectShape = (value) => typeof value === "object" && value !== null;
1262
+ var hasIterator = (value) => hasObjectShape(value) && typeof value[Symbol.iterator] === "function";
1263
+ var shallow = (previous, next) => {
1264
+ if (Object.is(previous, next)) return true;
1265
+ if (!hasObjectShape(previous) || !hasObjectShape(next)) {
1266
+ return false;
1267
+ }
1268
+ if (Array.isArray(previous) && Array.isArray(next)) {
1269
+ if (previous.length !== next.length) return false;
1270
+ for (let i = 0; i < previous.length; i++) {
1271
+ if (!Object.is(previous[i], next[i])) return false;
1272
+ }
1273
+ return true;
1274
+ }
1275
+ if (previous instanceof Map && next instanceof Map) {
1276
+ if (previous.size !== next.size) return false;
1277
+ for (const [key, value] of previous) {
1278
+ if (!next.has(key)) return false;
1279
+ if (!Object.is(value, next.get(key))) return false;
1280
+ }
1281
+ return true;
1282
+ }
1283
+ if (previous instanceof Set && next instanceof Set) {
1284
+ if (previous.size !== next.size) return false;
1285
+ for (const value of previous) {
1286
+ if (!next.has(value)) return false;
1287
+ }
1288
+ return true;
1289
+ }
1290
+ if (hasIterator(previous) && hasIterator(next)) {
1291
+ const a = previous[Symbol.iterator]();
1292
+ const b = next[Symbol.iterator]();
1293
+ while (true) {
1294
+ const ra = a.next();
1295
+ const rb = b.next();
1296
+ if (ra.done || rb.done) return ra.done === rb.done;
1297
+ if (!Object.is(ra.value, rb.value)) return false;
1298
+ }
1299
+ }
1300
+ const prevKeys = Object.keys(previous);
1301
+ const nextKeys = Object.keys(next);
1302
+ if (prevKeys.length !== nextKeys.length) return false;
1303
+ for (const key of prevKeys) {
1304
+ if (!Object.prototype.hasOwnProperty.call(next, key)) return false;
1305
+ if (!Object.is(previous[key], next[key])) return false;
1306
+ }
1307
+ return true;
1308
+ };
1309
+
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
+ // src/internal/hooks/useSelector.ts
1451
+ function useSelector(handle, selector, equalityFn) {
1452
+ const runtimeContext = (0, import_react5.useContext)(RuntimeContext);
1453
+ if (!runtimeContext) {
1454
+ throw new RuntimeProviderNotFoundError("useSelector");
1455
+ }
1456
+ const runtime = runtimeContext.runtime;
1457
+ const moduleRuntime = useModuleRuntime(handle);
1458
+ const actualSelector = selector ?? ((state) => state);
1459
+ const selectorReadQuery = (0, import_react5.useMemo)(
1460
+ () => typeof selector === "function" ? Logix5.ReadQuery.compile(selector) : void 0,
1461
+ [selector]
1462
+ );
1463
+ const actualEqualityFn = (0, import_react5.useMemo)(() => {
1464
+ if (typeof equalityFn === "function") return equalityFn;
1465
+ if (typeof selector !== "function") return Object.is;
1466
+ return selectorReadQuery?.equalsKind === "shallowStruct" ? shallow : Object.is;
1467
+ }, [equalityFn, selector, selectorReadQuery?.equalsKind]);
1468
+ const useStaticLane = typeof selector === "function" && selectorReadQuery?.lane === "static";
1469
+ 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(
1479
+ runtime,
1480
+ moduleRuntime,
1481
+ {
1482
+ lowPriorityDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
1483
+ lowPriorityMaxDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs
1484
+ }
1485
+ ),
1486
+ [
1487
+ moduleRuntime,
1488
+ runtime,
1489
+ runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
1490
+ runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs,
1491
+ selectorReadQuery,
1492
+ useStaticLane
1493
+ ]
1494
+ );
1495
+ const selected = (0, import_with_selector.useSyncExternalStoreWithSelector)(
1496
+ store.subscribe,
1497
+ store.getSnapshot,
1498
+ store.getSnapshot,
1499
+ useStaticLane ? (snapshot) => snapshot : (snapshot) => actualSelector(snapshot),
1500
+ actualEqualityFn
1501
+ );
1502
+ (0, import_react5.useEffect)(() => {
1503
+ if (!(0, import_Env.isDevEnv)() && !Logix5.Debug.isDevtoolsEnabled()) {
1504
+ return;
1505
+ }
1506
+ const instanceId = moduleRuntime.instanceId;
1507
+ let fieldPaths;
1508
+ let selectorKey;
1509
+ if (typeof selector === "function") {
1510
+ const meta = selector;
1511
+ const rawFieldPaths = meta.fieldPaths;
1512
+ if (Array.isArray(rawFieldPaths)) {
1513
+ const paths = rawFieldPaths.filter((p) => typeof p === "string");
1514
+ fieldPaths = paths.length > 0 ? paths.slice() : void 0;
1515
+ }
1516
+ const rawDebugKey = meta.debugKey;
1517
+ selectorKey = typeof rawDebugKey === "string" && rawDebugKey.length > 0 ? rawDebugKey : typeof selector.name === "string" && selector.name.length > 0 ? selector.name : void 0;
1518
+ }
1519
+ const effect = Logix5.Debug.record({
1520
+ type: "trace:react-selector",
1521
+ moduleId: moduleRuntime.moduleId,
1522
+ instanceId,
1523
+ data: {
1524
+ componentLabel: "useSelector",
1525
+ selectorKey,
1526
+ fieldPaths,
1527
+ selectorId: selectorReadQuery?.selectorId,
1528
+ lane: selectorReadQuery?.lane,
1529
+ producer: selectorReadQuery?.producer,
1530
+ fallbackReason: selectorReadQuery?.fallbackReason,
1531
+ readsDigest: selectorReadQuery?.readsDigest,
1532
+ equalsKind: selectorReadQuery?.equalsKind,
1533
+ strictModePhase: "commit"
1534
+ }
1535
+ });
1536
+ runtime.runFork(effect);
1537
+ }, [runtime, moduleRuntime, selector, selected, selectorReadQuery]);
1538
+ return selected;
1539
+ }
1540
+
1541
+ // src/internal/store/resolveImportedModuleRef.ts
1542
+ var Logix6 = __toESM(require("@logixjs/core"), 1);
1543
+ var getOrCreateWeakMap = (map, key, make) => {
1544
+ const cached = map.get(key);
1545
+ if (cached) return cached;
1546
+ const next = make();
1547
+ map.set(key, next);
1548
+ return next;
1549
+ };
1550
+ var cacheByRuntime = /* @__PURE__ */ new WeakMap();
1551
+ var resolveImportedModuleRef = (runtime, parentRuntime, module2) => {
1552
+ const byParent = getOrCreateWeakMap(
1553
+ cacheByRuntime,
1554
+ runtime,
1555
+ () => /* @__PURE__ */ new WeakMap()
1556
+ );
1557
+ const byModule = getOrCreateWeakMap(
1558
+ byParent,
1559
+ parentRuntime,
1560
+ () => /* @__PURE__ */ new WeakMap()
1561
+ );
1562
+ const cached = byModule.get(module2);
1563
+ if (cached) {
1564
+ return cached;
1565
+ }
1566
+ const importsScope = Logix6.InternalContracts.getImportsScope(parentRuntime);
1567
+ const childRuntime = importsScope.get(module2);
1568
+ if (childRuntime) {
1569
+ const dispatch = Object.assign(
1570
+ (action) => {
1571
+ runtime.runFork(childRuntime.dispatch(action));
1572
+ },
1573
+ {
1574
+ batch: (actions2) => {
1575
+ runtime.runFork(
1576
+ childRuntime.dispatchBatch(
1577
+ actions2
1578
+ )
1579
+ );
1580
+ },
1581
+ lowPriority: (action) => {
1582
+ runtime.runFork(
1583
+ childRuntime.dispatchLowPriority(action)
1584
+ );
1585
+ }
1586
+ }
1587
+ );
1588
+ const actions = makeModuleActions(dispatch);
1589
+ const dispatchers = makeModuleDispatchers(dispatch, module2.actions);
1590
+ const ref = {
1591
+ def: module2,
1592
+ runtime: childRuntime,
1593
+ dispatch,
1594
+ actions,
1595
+ dispatchers,
1596
+ imports: {
1597
+ get: (m) => resolveImportedModuleRef(runtime, childRuntime, m)
1598
+ },
1599
+ getState: childRuntime.getState,
1600
+ setState: childRuntime.setState,
1601
+ actions$: childRuntime.actions$,
1602
+ changes: childRuntime.changes,
1603
+ ref: childRuntime.ref
1604
+ };
1605
+ byModule.set(module2, ref);
1606
+ return ref;
1607
+ }
1608
+ const parentId = parentRuntime.moduleId;
1609
+ const tokenId = String(module2.id);
1610
+ const parentInstanceId = parentRuntime.instanceId;
1611
+ const fix = (0, import_Env.isDevEnv)() ? [
1612
+ "- Ensure the child is imported in the same scope.",
1613
+ ` Example: ${parentId}.implement({ imports: [${tokenId}.impl], ... })`,
1614
+ "- Ensure parentRuntime is an instance scope (not a ModuleTag singleton).",
1615
+ " Example: useModule(ParentImpl, { key }) / useModule(ParentImpl) / useLocalModule(ParentModule, ...)",
1616
+ "- If you intentionally want a singleton (not an imported child), use useModule(Child.tag) (ModuleTag) in the current React runtime environment.",
1617
+ "- If you intentionally want the root provider singleton (ignore RuntimeProvider.layer overrides), use runtime.runSync(Root.resolve(Child.tag))."
1618
+ ] : [];
1619
+ const err = new Error(
1620
+ (0, import_Env.isDevEnv)() ? [
1621
+ "[MissingImportedModuleError] Cannot resolve imported module from parent imports scope.",
1622
+ "",
1623
+ `tokenId: ${tokenId}`,
1624
+ "entrypoint: react.useImportedModule/imports.get",
1625
+ "mode: strict",
1626
+ `startScope: moduleId=${parentId}, instanceId=${parentInstanceId}`,
1627
+ "",
1628
+ "fix:",
1629
+ ...fix
1630
+ ].join("\n") : "[MissingImportedModuleError] imported module runtime not found"
1631
+ );
1632
+ err.tokenId = tokenId;
1633
+ err.entrypoint = "react.useImportedModule/imports.get";
1634
+ err.mode = "strict";
1635
+ err.startScope = {
1636
+ moduleId: parentId,
1637
+ instanceId: parentInstanceId
1638
+ };
1639
+ err.fix = fix;
1640
+ err.name = "MissingImportedModuleError";
1641
+ throw err;
1642
+ };
1643
+
1644
+ // src/internal/hooks/useStableId.ts
1645
+ var import_react6 = __toESM(require("react"), 1);
1646
+ var useStableId = () => {
1647
+ return import_react6.default.useId();
1648
+ };
1649
+
1650
+ // src/internal/hooks/useModule.ts
1651
+ 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";
1654
+ function useModule(handle, selectorOrOptions, equalityFn) {
1655
+ const runtimeBase = useRuntime();
1656
+ const runtimeContext = import_react7.default.useContext(RuntimeContext);
1657
+ if (!runtimeContext) {
1658
+ throw new RuntimeProviderNotFoundError("useModule");
1659
+ }
1660
+ const normalizedHandle = isModule(handle) ? handle.impl : isModuleDef(handle) ? handle.tag : handle;
1661
+ let selector;
1662
+ let options;
1663
+ if (isModuleImpl(normalizedHandle)) {
1664
+ if (typeof selectorOrOptions === "function") {
1665
+ selector = selectorOrOptions;
1666
+ } else if (selectorOrOptions && typeof selectorOrOptions === "object") {
1667
+ options = selectorOrOptions;
1668
+ }
1669
+ } else {
1670
+ if (typeof selectorOrOptions === "function" || selectorOrOptions === void 0) {
1671
+ selector = selectorOrOptions;
1672
+ } else if (selectorOrOptions && typeof selectorOrOptions === "object") {
1673
+ throw new Error("useModule(handle, options) \u4EC5\u652F\u6301 ModuleImpl \u53E5\u67C4");
1674
+ }
1675
+ }
1676
+ let runtime;
1677
+ if (isModuleImpl(normalizedHandle)) {
1678
+ const cache = import_react7.default.useMemo(
1679
+ () => getModuleCache(runtimeBase, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion),
1680
+ [runtimeBase, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion]
1681
+ );
1682
+ const deps = options?.deps ?? [];
1683
+ const depsHash = stableHash(deps);
1684
+ const explicitSuspend = options?.suspend === true;
1685
+ const suspend = explicitSuspend || options?.suspend !== false && runtimeContext.policy.moduleImplMode === "suspend";
1686
+ const gcTime = options?.gcTime ?? runtimeContext.reactConfigSnapshot.gcTime;
1687
+ let initTimeoutMs = suspend ? options?.initTimeoutMs : void 0;
1688
+ if (suspend && initTimeoutMs === void 0) {
1689
+ initTimeoutMs = runtimeContext.reactConfigSnapshot.initTimeoutMs;
1690
+ }
1691
+ if (explicitSuspend && (!options || !options.key)) {
1692
+ if ((0, import_Env.isDevEnv)()) {
1693
+ throw new Error(
1694
+ "[useModule] suspend:true \u6A21\u5F0F\u5FC5\u987B\u663E\u5F0F\u63D0\u4F9B options.key\uFF1B\u8BF7\u5728 Suspense \u8FB9\u754C\u5916\u751F\u6210\u7A33\u5B9A ID\uFF08\u4F8B\u5982 useId() \u6216\u4E1A\u52A1 id\uFF09\uFF0C\u5E76\u5728 useModule(Impl, { suspend: true, key }) \u4E2D\u4F20\u5165\u8BE5\u503C\u3002"
1695
+ );
1696
+ }
1697
+ }
1698
+ const componentId = useStableId();
1699
+ const moduleId = normalizedHandle.module.id ?? "ModuleImpl";
1700
+ const preloadKey = runtimeContext.policy.preload?.keysByModuleId.get(moduleId);
1701
+ const baseKey = preloadKey ?? options?.key ?? (suspend ? `impl:${moduleId}` : `impl:${moduleId}:${componentId}`);
1702
+ const key = depsHash ? `${baseKey}:${depsHash}` : baseKey;
1703
+ const ownerId = moduleId;
1704
+ const baseFactory = import_react7.default.useMemo(
1705
+ () => (scope) => import_effect8.Layer.buildWithScope(normalizedHandle.layer, scope).pipe(
1706
+ import_effect8.Effect.map(
1707
+ (context) => import_effect8.Context.get(context, normalizedHandle.module)
1708
+ )
1709
+ ),
1710
+ [normalizedHandle]
1711
+ );
1712
+ const factory = import_react7.default.useMemo(() => {
1713
+ if (!suspend || initTimeoutMs === void 0) {
1714
+ return baseFactory;
1715
+ }
1716
+ 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
+ })
1721
+ );
1722
+ }, [baseFactory, suspend, initTimeoutMs, ownerId]);
1723
+ const moduleRuntime = suspend ? cache.read(key, factory, gcTime, ownerId, {
1724
+ entrypoint: "react.useModule",
1725
+ policyMode: runtimeContext.policy.mode,
1726
+ yield: runtimeContext.policy.yield
1727
+ }) : cache.readSync(key, factory, gcTime, ownerId, {
1728
+ entrypoint: "react.useModule",
1729
+ policyMode: runtimeContext.policy.mode,
1730
+ warnSyncBlockingThresholdMs: 5
1731
+ });
1732
+ import_react7.default.useEffect(() => cache.retain(key), [cache, key]);
1733
+ runtime = moduleRuntime;
1734
+ } else {
1735
+ runtime = useModuleRuntime(normalizedHandle);
1736
+ }
1737
+ import_react7.default.useEffect(() => {
1738
+ if (!isModuleImpl(normalizedHandle)) {
1739
+ return;
1740
+ }
1741
+ const opt = options;
1742
+ const label = opt && "label" in opt && opt.label || opt && opt.key;
1743
+ if (!label) {
1744
+ return;
1745
+ }
1746
+ const effect = Logix7.Debug.record({
1747
+ type: "trace:instanceLabel",
1748
+ moduleId: normalizedHandle.module.id,
1749
+ instanceId: runtime.instanceId,
1750
+ data: { label }
1751
+ });
1752
+ runtimeBase.runFork(effect);
1753
+ }, [runtimeBase, runtime, normalizedHandle, options]);
1754
+ import_react7.default.useEffect(() => {
1755
+ if (!(0, import_Env.isDevEnv)() && !Logix7.Debug.isDevtoolsEnabled()) {
1756
+ return;
1757
+ }
1758
+ if (!runtime.instanceId) {
1759
+ return;
1760
+ }
1761
+ const effect = Logix7.Debug.record({
1762
+ type: "trace:react-render",
1763
+ moduleId: runtime.moduleId,
1764
+ instanceId: runtime.instanceId,
1765
+ data: {
1766
+ componentLabel: "useModule",
1767
+ strictModePhase: "commit"
1768
+ }
1769
+ });
1770
+ runtimeBase.runFork(effect);
1771
+ }, [runtimeBase, runtime]);
1772
+ if (selector) {
1773
+ if (isModuleImpl(normalizedHandle)) {
1774
+ return useSelector(runtime, selector, equalityFn);
1775
+ }
1776
+ return useSelector(normalizedHandle, selector, equalityFn);
1777
+ }
1778
+ const def = import_react7.default.useMemo(() => {
1779
+ if (isModule(handle) || isModuleDef(handle)) {
1780
+ return handle;
1781
+ }
1782
+ if (isModuleRef(handle)) {
1783
+ return handle.def;
1784
+ }
1785
+ if (isModuleImpl(handle)) {
1786
+ return handle.module;
1787
+ }
1788
+ if (handle && (typeof handle === "object" || typeof handle === "function") && handle._kind === "ModuleTag") {
1789
+ return handle;
1790
+ }
1791
+ if (isModuleImpl(normalizedHandle)) {
1792
+ return normalizedHandle.module;
1793
+ }
1794
+ if (isModuleRef(normalizedHandle)) {
1795
+ return normalizedHandle.def;
1796
+ }
1797
+ if (normalizedHandle && (typeof normalizedHandle === "object" || typeof normalizedHandle === "function") && normalizedHandle._kind === "ModuleTag") {
1798
+ return normalizedHandle;
1799
+ }
1800
+ return void 0;
1801
+ }, [handle, normalizedHandle]);
1802
+ const tokens = import_react7.default.useMemo(() => {
1803
+ if (!def || typeof def !== "object" && typeof def !== "function") {
1804
+ return void 0;
1805
+ }
1806
+ const candidate = def;
1807
+ if (!candidate.actions || typeof candidate.actions !== "object") {
1808
+ return void 0;
1809
+ }
1810
+ return candidate.actions;
1811
+ }, [def]);
1812
+ const dispatch = import_react7.default.useMemo(() => {
1813
+ const base = (action) => {
1814
+ runtimeBase.runFork(runtime.dispatch(action));
1815
+ };
1816
+ return Object.assign(base, {
1817
+ batch: (actions2) => {
1818
+ runtimeBase.runFork(runtime.dispatchBatch(actions2));
1819
+ },
1820
+ lowPriority: (action) => {
1821
+ runtimeBase.runFork(runtime.dispatchLowPriority(action));
1822
+ }
1823
+ });
1824
+ }, [runtimeBase, runtime]);
1825
+ const extendTag = import_react7.default.useMemo(() => {
1826
+ if (isModuleImpl(normalizedHandle)) {
1827
+ return normalizedHandle.module;
1828
+ }
1829
+ return normalizedHandle;
1830
+ }, [normalizedHandle]);
1831
+ const actions = import_react7.default.useMemo(() => makeModuleActions(dispatch), [dispatch]);
1832
+ const dispatchers = import_react7.default.useMemo(
1833
+ () => tokens ? makeModuleDispatchers(dispatch, tokens) : makeModuleDispatchers(dispatch),
1834
+ [dispatch, tokens]
1835
+ );
1836
+ return import_react7.default.useMemo(() => {
1837
+ const base = {
1838
+ def,
1839
+ runtime,
1840
+ dispatch,
1841
+ actions,
1842
+ dispatchers,
1843
+ imports: {
1844
+ get: (module2) => resolveImportedModuleRef(runtimeBase, runtime, module2)
1845
+ },
1846
+ getState: runtime.getState,
1847
+ setState: runtime.setState,
1848
+ actions$: runtime.actions$,
1849
+ changes: runtime.changes,
1850
+ ref: runtime.ref
1851
+ };
1852
+ return applyHandleExtend(extendTag, runtime, base);
1853
+ }, [runtimeBase, runtime, dispatch, actions, dispatchers, extendTag, def]);
1854
+ }
1855
+
1856
+ // src/internal/hooks/useLocalModule.ts
1857
+ var import_react8 = __toESM(require("react"), 1);
1858
+ var Logix8 = __toESM(require("@logixjs/core"), 1);
1859
+ var import_effect9 = require("effect");
1860
+ function isModuleTag(source) {
1861
+ if (!source || typeof source !== "object" && typeof source !== "function") {
1862
+ return false;
1863
+ }
1864
+ const candidate = source;
1865
+ return candidate._kind === "ModuleTag";
1866
+ }
1867
+ function useLocalModule(source, second) {
1868
+ const runtime = useRuntime();
1869
+ const runtimeContext = import_react8.default.useContext(RuntimeContext);
1870
+ if (!runtimeContext) {
1871
+ throw new RuntimeProviderNotFoundError("useLocalModule");
1872
+ }
1873
+ const cache = (0, import_react8.useMemo)(
1874
+ () => getModuleCache(runtime, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion),
1875
+ [runtime, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion]
1876
+ );
1877
+ const componentId = useStableId();
1878
+ const moduleTag = import_react8.default.useMemo(() => {
1879
+ if (Logix8.Module.is(source)) {
1880
+ return source.tag;
1881
+ }
1882
+ if (isModuleTag(source)) {
1883
+ return source;
1884
+ }
1885
+ return null;
1886
+ }, [source]);
1887
+ const def = import_react8.default.useMemo(() => {
1888
+ if (Logix8.Module.is(source) || isModuleTag(source)) {
1889
+ return source;
1890
+ }
1891
+ return void 0;
1892
+ }, [source]);
1893
+ const isModule2 = moduleTag !== null;
1894
+ const moduleOptions = isModule2 ? second : void 0;
1895
+ const deps = isModule2 ? moduleOptions?.deps ?? [] : second ?? [];
1896
+ const { key, ownerId } = (0, import_react8.useMemo)(() => {
1897
+ const depsHash = stableHash(deps);
1898
+ if (isModule2) {
1899
+ const module2 = moduleTag;
1900
+ const baseKey = moduleOptions?.key ?? module2.id ?? "module";
1901
+ return {
1902
+ key: `local:${baseKey}:${componentId}:${depsHash}`,
1903
+ ownerId: module2.id ?? "Module"
1904
+ };
1905
+ }
1906
+ return {
1907
+ key: `local:factory:${componentId}:${depsHash}`,
1908
+ ownerId: void 0
1909
+ };
1910
+ }, [isModule2, moduleTag, moduleOptions?.key, deps, componentId]);
1911
+ const factory = (0, import_react8.useMemo)(() => {
1912
+ if (isModule2) {
1913
+ return createModuleTagFactory(moduleTag, moduleOptions);
1914
+ }
1915
+ const factoryFn = source;
1916
+ return (scope) => factoryFn().pipe(import_effect9.Scope.extend(scope));
1917
+ }, [isModule2, moduleTag, source, moduleOptions]);
1918
+ const moduleRuntime = cache.readSync(key, factory, void 0, ownerId, {
1919
+ entrypoint: "react.useLocalModule",
1920
+ policyMode: runtimeContext.policy.mode,
1921
+ warnSyncBlockingThresholdMs: 5
1922
+ });
1923
+ (0, import_react8.useEffect)(() => cache.retain(key), [cache, key]);
1924
+ const dispatch = (0, import_react8.useMemo)(() => {
1925
+ const base = (action) => {
1926
+ runtime.runFork(moduleRuntime.dispatch(action));
1927
+ };
1928
+ return Object.assign(base, {
1929
+ batch: (actions2) => {
1930
+ runtime.runFork(moduleRuntime.dispatchBatch(actions2));
1931
+ },
1932
+ lowPriority: (action) => {
1933
+ runtime.runFork(moduleRuntime.dispatchLowPriority(action));
1934
+ }
1935
+ });
1936
+ }, [runtime, moduleRuntime]);
1937
+ const tokens = (0, import_react8.useMemo)(() => {
1938
+ if (!def || typeof def !== "object" && typeof def !== "function") {
1939
+ return void 0;
1940
+ }
1941
+ const candidate = def;
1942
+ if (!candidate.actions || typeof candidate.actions !== "object") {
1943
+ return void 0;
1944
+ }
1945
+ return candidate.actions;
1946
+ }, [def]);
1947
+ const actions = (0, import_react8.useMemo)(() => makeModuleActions(dispatch), [dispatch]);
1948
+ const dispatchers = (0, import_react8.useMemo)(
1949
+ () => tokens ? makeModuleDispatchers(dispatch, tokens) : makeModuleDispatchers(dispatch),
1950
+ [dispatch, tokens]
1951
+ );
1952
+ return (0, import_react8.useMemo)(
1953
+ () => ({
1954
+ def,
1955
+ runtime: moduleRuntime,
1956
+ dispatch,
1957
+ actions,
1958
+ dispatchers,
1959
+ imports: {
1960
+ get: (module2) => resolveImportedModuleRef(runtime, moduleRuntime, module2)
1961
+ },
1962
+ getState: moduleRuntime.getState,
1963
+ setState: moduleRuntime.setState,
1964
+ actions$: moduleRuntime.actions$,
1965
+ changes: moduleRuntime.changes,
1966
+ ref: moduleRuntime.ref
1967
+ }),
1968
+ [runtime, moduleRuntime, dispatch, actions, dispatchers, def]
1969
+ );
1970
+ }
1971
+ function createModuleTagFactory(module2, options) {
1972
+ if (!options || options.initial === void 0) {
1973
+ throw new Error("useLocalModule(module, options) \u9700\u8981\u63D0\u4F9B initial \u72B6\u6001");
1974
+ }
1975
+ const logics = options.logics ?? [];
1976
+ return (scope) => import_effect9.Layer.buildWithScope(module2.live(options.initial, ...logics), scope).pipe(
1977
+ import_effect9.Effect.map((context) => {
1978
+ const runtime = import_effect9.Context.get(context, module2);
1979
+ return runtime;
1980
+ })
1981
+ );
1982
+ }
1983
+
1984
+ // src/internal/hooks/useLayerModule.ts
1985
+ var import_react9 = __toESM(require("react"), 1);
1986
+ var import_effect10 = require("effect");
1987
+ function useLayerModule(module2, layer, deps = []) {
1988
+ const factory = import_react9.default.useCallback(
1989
+ () => import_effect10.Layer.build(layer).pipe(
1990
+ import_effect10.Effect.scoped,
1991
+ import_effect10.Effect.map((context) => import_effect10.Context.get(context, module2))
1992
+ ),
1993
+ // layer/module are typically constants; deps lets callers opt into rebuilding when needed.
1994
+ [layer, module2]
1995
+ );
1996
+ return useLocalModule(factory, deps);
1997
+ }
1998
+
1999
+ // src/internal/hooks/useDispatch.ts
2000
+ var import_react10 = require("react");
2001
+ function useDispatch(handle) {
2002
+ const runtime = useRuntime();
2003
+ const moduleRuntime = useModuleRuntime(handle);
2004
+ return (0, import_react10.useMemo)(() => {
2005
+ const base = (action) => {
2006
+ runtime.runFork(moduleRuntime.dispatch(action));
2007
+ };
2008
+ return Object.assign(base, {
2009
+ batch: (actions) => {
2010
+ runtime.runFork(moduleRuntime.dispatchBatch(actions));
2011
+ },
2012
+ lowPriority: (action) => {
2013
+ runtime.runFork(moduleRuntime.dispatchLowPriority(action));
2014
+ }
2015
+ });
2016
+ }, [runtime, moduleRuntime]);
2017
+ }
2018
+
2019
+ // src/internal/hooks/useModuleList.ts
2020
+ var import_react11 = require("react");
2021
+ function useModuleList(items, keyFn, factory) {
2022
+ const cache = (0, import_react11.useMemo)(() => /* @__PURE__ */ new Map(), []);
2023
+ const keyFnRef = (0, import_react11.useRef)(keyFn);
2024
+ keyFnRef.current = keyFn;
2025
+ const factoryRef = (0, import_react11.useRef)(factory);
2026
+ factoryRef.current = factory;
2027
+ return (0, import_react11.useMemo)(() => {
2028
+ return items.map((item) => {
2029
+ const key = keyFnRef.current(item);
2030
+ if (!cache.has(key)) {
2031
+ cache.set(key, factoryRef.current(key, item));
2032
+ }
2033
+ return cache.get(key);
2034
+ });
2035
+ }, [items, cache]);
2036
+ }
2037
+
2038
+ // src/internal/hooks/useImportedModule.ts
2039
+ var import_react12 = __toESM(require("react"), 1);
2040
+ function useImportedModule(parent, module2) {
2041
+ const runtime = useRuntime();
2042
+ const parentRuntime = useModuleRuntime(parent);
2043
+ return import_react12.default.useMemo(() => resolveImportedModuleRef(runtime, parentRuntime, module2), [runtime, parentRuntime, module2]);
2044
+ }
2045
+
2046
+ // src/internal/hooks/useProcesses.ts
2047
+ var import_react13 = __toESM(require("react"), 1);
2048
+ var import_effect11 = require("effect");
2049
+ var Logix9 = __toESM(require("@logixjs/core"), 1);
2050
+ var ProcessSubtreeRegistry = class {
2051
+ constructor(runtime) {
2052
+ this.runtime = runtime;
2053
+ this.entries = /* @__PURE__ */ new Map();
2054
+ }
2055
+ retain(args) {
2056
+ const existing = this.entries.get(args.key);
2057
+ if (existing) {
2058
+ if (existing.signature !== args.signature) {
2059
+ throw new Error(
2060
+ `[useProcesses] subtreeId "${args.key}" has already been claimed by a different process set. previous="${existing.signature}" current="${args.signature}". Use a different subtreeId or keep the processes list stable for the same subtree.`
2061
+ );
2062
+ }
2063
+ existing.refCount += 1;
2064
+ if (existing.gcTimeout) {
2065
+ clearTimeout(existing.gcTimeout);
2066
+ existing.gcTimeout = void 0;
2067
+ }
2068
+ return () => this.release({ key: args.key, gcTime: args.gcTime });
2069
+ }
2070
+ const scope = import_effect11.Effect.runSync(import_effect11.Scope.make());
2071
+ const entry = {
2072
+ key: args.key,
2073
+ signature: args.signature,
2074
+ scope,
2075
+ refCount: 1
2076
+ };
2077
+ this.entries.set(args.key, entry);
2078
+ args.install(scope);
2079
+ return () => this.release({ key: args.key, gcTime: args.gcTime });
2080
+ }
2081
+ release(args) {
2082
+ const entry = this.entries.get(args.key);
2083
+ if (!entry) return;
2084
+ entry.refCount = Math.max(0, entry.refCount - 1);
2085
+ if (entry.refCount > 0) return;
2086
+ this.scheduleGC(entry, args.gcTime);
2087
+ }
2088
+ scheduleGC(entry, gcTime) {
2089
+ if (entry.gcTimeout) return;
2090
+ if (!Number.isFinite(gcTime)) {
2091
+ return;
2092
+ }
2093
+ const timeoutMs = gcTime <= 0 ? 0 : gcTime;
2094
+ entry.gcTimeout = setTimeout(() => {
2095
+ const current = this.entries.get(entry.key);
2096
+ if (!current || current !== entry) return;
2097
+ if (current.refCount > 0) return;
2098
+ void this.runtime.runPromise(import_effect11.Scope.close(entry.scope, import_effect11.Exit.void)).catch(() => {
2099
+ });
2100
+ this.entries.delete(entry.key);
2101
+ }, timeoutMs);
2102
+ }
2103
+ };
2104
+ var RUNTIME_PROCESS_REGISTRY = /* @__PURE__ */ new WeakMap();
2105
+ var getRegistry = (runtime) => {
2106
+ const existing = RUNTIME_PROCESS_REGISTRY.get(runtime);
2107
+ if (existing) return existing;
2108
+ const created = new ProcessSubtreeRegistry(runtime);
2109
+ RUNTIME_PROCESS_REGISTRY.set(runtime, created);
2110
+ return created;
2111
+ };
2112
+ var stableProcessSignature = (processes) => {
2113
+ const ids = [];
2114
+ for (let i = 0; i < processes.length; i++) {
2115
+ const def = Logix9.Process.getDefinition(processes[i]);
2116
+ ids.push(def?.processId ?? `legacy#${i}`);
2117
+ }
2118
+ return ids.join("|");
2119
+ };
2120
+ function useProcesses(processes, options) {
2121
+ const context = (0, import_react13.useContext)(RuntimeContext);
2122
+ if (!context) {
2123
+ throw new RuntimeProviderNotFoundError("useProcesses");
2124
+ }
2125
+ const isDev = (0, import_Env.isDevEnv)();
2126
+ const lastProcessesRef = (0, import_react13.useRef)(null);
2127
+ const shallowEqualProcesses = (a, b) => !!a && !!b && a.length === b.length && a.every((item, idx) => item === b[idx]);
2128
+ (0, import_react13.useEffect)(() => {
2129
+ if (!isDev) return;
2130
+ if (!lastProcessesRef.current) {
2131
+ lastProcessesRef.current = processes;
2132
+ return;
2133
+ }
2134
+ if (lastProcessesRef.current !== processes && !shallowEqualProcesses(lastProcessesRef.current, processes)) {
2135
+ console.warn(
2136
+ "[useProcesses] received a new processes list. Memoize the list (useMemo) to avoid unnecessary install/uninstall churn."
2137
+ );
2138
+ }
2139
+ lastProcessesRef.current = processes;
2140
+ }, [isDev, processes]);
2141
+ const defaultSubtreeId = import_react13.default.useId();
2142
+ const subtreeId = options?.subtreeId ?? `ui:${defaultSubtreeId}`;
2143
+ const signature = (0, import_react13.useMemo)(() => stableProcessSignature(processes), [processes]);
2144
+ const gcTime = options?.gcTime ?? context.reactConfigSnapshot.gcTime;
2145
+ const mode = options?.mode ?? "switch";
2146
+ const deps = options?.deps ? [...options.deps, context.runtime, subtreeId, signature, gcTime, mode] : [context.runtime, subtreeId, signature, gcTime, mode];
2147
+ (0, import_react13.useEffect)(() => {
2148
+ if (!processes || processes.length === 0) {
2149
+ return;
2150
+ }
2151
+ const runtime = context.runtime;
2152
+ const registry = getRegistry(runtime);
2153
+ return registry.retain({
2154
+ key: subtreeId,
2155
+ signature,
2156
+ gcTime,
2157
+ install: (scope) => {
2158
+ const program = import_effect11.Effect.forEach(
2159
+ processes,
2160
+ (process) => Logix9.InternalContracts.installProcess(process, {
2161
+ scope: { type: "uiSubtree", subtreeId },
2162
+ enabled: true,
2163
+ installedAt: "uiSubtree",
2164
+ mode
2165
+ }).pipe(
2166
+ import_effect11.Effect.flatMap((installation) => {
2167
+ if (installation !== void 0) {
2168
+ return import_effect11.Effect.void;
2169
+ }
2170
+ return import_effect11.Effect.forkScoped(process).pipe(import_effect11.Effect.asVoid);
2171
+ }),
2172
+ import_effect11.Effect.catchAll(() => import_effect11.Effect.forkScoped(process).pipe(import_effect11.Effect.asVoid))
2173
+ ),
2174
+ { discard: true }
2175
+ ).pipe(import_effect11.Effect.provideService(import_effect11.Scope.Scope, scope));
2176
+ void runtime.runPromise(program).catch(() => {
2177
+ });
2178
+ }
2179
+ });
2180
+ }, deps);
2181
+ }
2182
+ // Annotate the CommonJS export names for ESM import in node:
2183
+ 0 && (module.exports = {
2184
+ shallow,
2185
+ useDispatch,
2186
+ useImportedModule,
2187
+ useLayerModule,
2188
+ useLocalModule,
2189
+ useModule,
2190
+ useModuleList,
2191
+ useProcesses,
2192
+ useRuntime,
2193
+ useSelector
2194
+ });