@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.
- package/README.md +64 -0
- package/dist/Hooks.cjs +2194 -0
- package/dist/Hooks.d.cts +77 -0
- package/dist/Hooks.d.ts +77 -0
- package/dist/Hooks.js +27 -0
- package/dist/ModuleRef-wZSQ3Wwo.d.cts +73 -0
- package/dist/ModuleRef-wZSQ3Wwo.d.ts +73 -0
- package/dist/ModuleScope.cjs +2695 -0
- package/dist/ModuleScope.d.cts +62 -0
- package/dist/ModuleScope.d.ts +62 -0
- package/dist/ModuleScope.js +9 -0
- package/dist/Platform.cjs +60 -0
- package/dist/Platform.d.cts +6 -0
- package/dist/Platform.d.ts +6 -0
- package/dist/Platform.js +6 -0
- package/dist/ReactPlatform.cjs +2813 -0
- package/dist/ReactPlatform.d.cts +40 -0
- package/dist/ReactPlatform.d.ts +40 -0
- package/dist/ReactPlatform.js +11 -0
- package/dist/RuntimeProvider.cjs +1618 -0
- package/dist/RuntimeProvider.d.cts +66 -0
- package/dist/RuntimeProvider.d.ts +66 -0
- package/dist/RuntimeProvider.js +8 -0
- package/dist/chunk-2WFULYPJ.js +856 -0
- package/dist/chunk-4G7H66OY.js +54 -0
- package/dist/chunk-G5MRIFKK.js +95 -0
- package/dist/chunk-JXAJTWSZ.js +773 -0
- package/dist/chunk-PYWHL7TA.js +351 -0
- package/dist/chunk-UFFCJGSZ.js +981 -0
- package/dist/chunk-VFWWMK67.js +0 -0
- package/dist/chunk-ZANGOPUQ.js +34 -0
- package/dist/global.d.cjs +1 -0
- package/dist/global.d.d.cts +9 -0
- package/dist/global.d.d.ts +9 -0
- package/dist/global.d.js +0 -0
- package/dist/index.cjs +3118 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +44 -0
- package/dist/useDispatch-BnzYVkRE.d.ts +81 -0
- package/dist/useDispatch-CnO5-66H.d.cts +81 -0
- package/package.json +58 -0
|
@@ -0,0 +1,2695 @@
|
|
|
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/ModuleScope.ts
|
|
31
|
+
var ModuleScope_exports = {};
|
|
32
|
+
__export(ModuleScope_exports, {
|
|
33
|
+
ModuleScope: () => ModuleScope
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(ModuleScope_exports);
|
|
36
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
37
|
+
var Logix10 = __toESM(require("@logixjs/core"), 1);
|
|
38
|
+
|
|
39
|
+
// src/internal/hooks/useModule.ts
|
|
40
|
+
var import_react7 = __toESM(require("react"), 1);
|
|
41
|
+
var Logix7 = __toESM(require("@logixjs/core"), 1);
|
|
42
|
+
var import_effect8 = require("effect");
|
|
43
|
+
|
|
44
|
+
// src/internal/hooks/useModuleRuntime.ts
|
|
45
|
+
var import_react4 = require("react");
|
|
46
|
+
var Logix4 = __toESM(require("@logixjs/core"), 1);
|
|
47
|
+
var import_effect5 = require("effect");
|
|
48
|
+
|
|
49
|
+
// src/internal/hooks/useRuntime.ts
|
|
50
|
+
var import_react3 = require("react");
|
|
51
|
+
var import_effect2 = require("effect");
|
|
52
|
+
|
|
53
|
+
// src/internal/provider/ReactContext.ts
|
|
54
|
+
var import_react = require("react");
|
|
55
|
+
var RuntimeContext = (0, import_react.createContext)(null);
|
|
56
|
+
|
|
57
|
+
// src/internal/provider/env.ts
|
|
58
|
+
var import_Env = require("@logixjs/core/Env");
|
|
59
|
+
|
|
60
|
+
// src/internal/provider/runtimeBindings.ts
|
|
61
|
+
var import_react2 = require("react");
|
|
62
|
+
var import_effect = require("effect");
|
|
63
|
+
var Logix = __toESM(require("@logixjs/core"), 1);
|
|
64
|
+
var toErrorString = (error) => error instanceof Error ? error.stack ?? error.message : String(error);
|
|
65
|
+
var debugScopeCloseFailure = (error) => {
|
|
66
|
+
if (!(0, import_Env.isDevEnv)()) return;
|
|
67
|
+
console.debug("[RuntimeProvider] Scope.close failed", toErrorString(error));
|
|
68
|
+
};
|
|
69
|
+
var useLayerBinding = (runtime, layer, enabled, onError) => {
|
|
70
|
+
const activeBindingRef = (0, import_react2.useRef)(null);
|
|
71
|
+
const [state, setState] = (0, import_react2.useState)(() => ({
|
|
72
|
+
binding: null,
|
|
73
|
+
isLoading: enabled && !!layer,
|
|
74
|
+
runtime,
|
|
75
|
+
layer,
|
|
76
|
+
enabled
|
|
77
|
+
}));
|
|
78
|
+
(0, import_react2.useEffect)(() => {
|
|
79
|
+
if (!enabled || !layer) {
|
|
80
|
+
const current2 = activeBindingRef.current;
|
|
81
|
+
if (current2) {
|
|
82
|
+
activeBindingRef.current = null;
|
|
83
|
+
void runtime.runPromise(import_effect.Scope.close(current2.scope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
|
|
84
|
+
}
|
|
85
|
+
setState((prev) => {
|
|
86
|
+
if (prev.binding === null && prev.isLoading === false && prev.layer === void 0 && prev.enabled === enabled) {
|
|
87
|
+
return prev;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
binding: null,
|
|
91
|
+
isLoading: false,
|
|
92
|
+
runtime: prev.runtime,
|
|
93
|
+
layer: void 0,
|
|
94
|
+
enabled
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const current = activeBindingRef.current;
|
|
100
|
+
if (current && current.runtime === runtime && current.layer === layer && current.enabled === enabled) {
|
|
101
|
+
setState({
|
|
102
|
+
binding: current,
|
|
103
|
+
isLoading: false,
|
|
104
|
+
runtime,
|
|
105
|
+
layer,
|
|
106
|
+
enabled
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const previousBinding = current ?? state.binding;
|
|
111
|
+
if ((0, import_Env.isDevEnv)() && previousBinding && previousBinding.layer !== layer && enabled && layer) {
|
|
112
|
+
console.warn(
|
|
113
|
+
"[RuntimeProvider] Rebuilding layer due to a new layer reference. Memoize the Layer in the caller to avoid repeated rebuilds and resource churn."
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (current) {
|
|
117
|
+
activeBindingRef.current = null;
|
|
118
|
+
void runtime.runPromise(import_effect.Scope.close(current.scope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
|
|
119
|
+
}
|
|
120
|
+
let cancelled = false;
|
|
121
|
+
setState({
|
|
122
|
+
binding: null,
|
|
123
|
+
isLoading: true,
|
|
124
|
+
runtime,
|
|
125
|
+
layer,
|
|
126
|
+
enabled
|
|
127
|
+
});
|
|
128
|
+
const newScope = import_effect.Effect.runSync(import_effect.Scope.make());
|
|
129
|
+
const buildEffect = import_effect.Effect.gen(function* () {
|
|
130
|
+
const context = yield* import_effect.Layer.buildWithScope(layer, newScope);
|
|
131
|
+
const applyEnv = (effect) => import_effect.Effect.mapInputContext(
|
|
132
|
+
import_effect.Scope.extend(effect, newScope),
|
|
133
|
+
(parent) => import_effect.Context.merge(parent, context)
|
|
134
|
+
);
|
|
135
|
+
const loggers = yield* applyEnv(import_effect.FiberRef.get(import_effect.FiberRef.currentLoggers));
|
|
136
|
+
const logLevel = yield* applyEnv(import_effect.FiberRef.get(import_effect.FiberRef.currentLogLevel));
|
|
137
|
+
const debugSinks = yield* applyEnv(
|
|
138
|
+
import_effect.FiberRef.get(Logix.Debug.internal.currentDebugSinks)
|
|
139
|
+
);
|
|
140
|
+
return { context, loggers, logLevel, debugSinks };
|
|
141
|
+
});
|
|
142
|
+
const assignBinding = (result) => {
|
|
143
|
+
if (cancelled) {
|
|
144
|
+
return runtime.runPromise(import_effect.Scope.close(newScope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
|
|
145
|
+
}
|
|
146
|
+
const previous = activeBindingRef.current;
|
|
147
|
+
const newBinding = {
|
|
148
|
+
context: result.context,
|
|
149
|
+
loggers: result.loggers,
|
|
150
|
+
logLevel: result.logLevel,
|
|
151
|
+
debugSinks: result.debugSinks,
|
|
152
|
+
scope: newScope,
|
|
153
|
+
runtime,
|
|
154
|
+
layer,
|
|
155
|
+
enabled
|
|
156
|
+
};
|
|
157
|
+
activeBindingRef.current = newBinding;
|
|
158
|
+
setState({
|
|
159
|
+
binding: newBinding,
|
|
160
|
+
isLoading: false,
|
|
161
|
+
runtime,
|
|
162
|
+
layer,
|
|
163
|
+
enabled
|
|
164
|
+
});
|
|
165
|
+
if (previous) {
|
|
166
|
+
return runtime.runPromise(import_effect.Scope.close(previous.scope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
|
|
167
|
+
}
|
|
168
|
+
return Promise.resolve();
|
|
169
|
+
};
|
|
170
|
+
let builtSync = false;
|
|
171
|
+
try {
|
|
172
|
+
const result = runtime.runSync(buildEffect);
|
|
173
|
+
builtSync = true;
|
|
174
|
+
void assignBinding(result);
|
|
175
|
+
} catch {
|
|
176
|
+
}
|
|
177
|
+
if (!builtSync) {
|
|
178
|
+
void runtime.runPromise(buildEffect).then(assignBinding).catch((error) => {
|
|
179
|
+
if (onError) {
|
|
180
|
+
const cause = import_effect.Cause.die(error);
|
|
181
|
+
runtime.runFork(
|
|
182
|
+
onError(cause, { source: "provider", phase: "provider.layer.build" }).pipe(
|
|
183
|
+
import_effect.Effect.catchAllCause(() => import_effect.Effect.void)
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
void runtime.runPromise(import_effect.Scope.close(newScope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
|
|
188
|
+
if (!cancelled) {
|
|
189
|
+
console.error("[RuntimeProvider] Failed to build layer", error);
|
|
190
|
+
setState({
|
|
191
|
+
binding: null,
|
|
192
|
+
isLoading: false,
|
|
193
|
+
runtime,
|
|
194
|
+
layer,
|
|
195
|
+
enabled
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return () => {
|
|
201
|
+
cancelled = true;
|
|
202
|
+
const current2 = activeBindingRef.current;
|
|
203
|
+
if (current2) {
|
|
204
|
+
activeBindingRef.current = null;
|
|
205
|
+
void runtime.runPromise(import_effect.Scope.close(current2.scope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
void runtime.runPromise(import_effect.Scope.close(newScope, import_effect.Exit.void)).catch(debugScopeCloseFailure);
|
|
209
|
+
};
|
|
210
|
+
}, [runtime, layer, enabled, onError]);
|
|
211
|
+
const isCurrentBinding = state.binding !== null && state.runtime === runtime && state.layer === layer && state.enabled === enabled && enabled && !!layer;
|
|
212
|
+
return {
|
|
213
|
+
binding: isCurrentBinding ? state.binding : null,
|
|
214
|
+
isLoading: isCurrentBinding ? state.isLoading : enabled && !!layer
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
var createRuntimeAdapter = (runtime, contexts, scopes, loggerSets, logLevels, debugSinks) => {
|
|
218
|
+
if (contexts.length === 0 && scopes.length === 0 && loggerSets.length === 0 && logLevels.length === 0 && debugSinks.length === 0) {
|
|
219
|
+
return runtime;
|
|
220
|
+
}
|
|
221
|
+
const applyContexts = (effect) => (
|
|
222
|
+
// First inherit Provider scopes via scope.extend (preserving FiberRef/Logger changes),
|
|
223
|
+
// then merge Context via mapInputContext (inner overrides outer).
|
|
224
|
+
contexts.reduceRight(
|
|
225
|
+
(acc, ctx) => import_effect.Effect.mapInputContext(
|
|
226
|
+
acc,
|
|
227
|
+
(parent) => import_effect.Context.merge(parent, ctx)
|
|
228
|
+
),
|
|
229
|
+
scopes.reduceRight(
|
|
230
|
+
(acc, scope) => import_effect.Scope.extend(acc, scope),
|
|
231
|
+
effect
|
|
232
|
+
)
|
|
233
|
+
)
|
|
234
|
+
);
|
|
235
|
+
const applyLoggers = (effect) => {
|
|
236
|
+
const last = loggerSets.length > 0 ? loggerSets[loggerSets.length - 1] : null;
|
|
237
|
+
const logLevel = logLevels.length > 0 ? logLevels[logLevels.length - 1] : null;
|
|
238
|
+
const sinks = debugSinks.length > 0 ? debugSinks[debugSinks.length - 1] : null;
|
|
239
|
+
let result = effect;
|
|
240
|
+
if (last) {
|
|
241
|
+
result = import_effect.Effect.locally(import_effect.FiberRef.currentLoggers, last)(result);
|
|
242
|
+
}
|
|
243
|
+
if (logLevel) {
|
|
244
|
+
result = import_effect.Effect.locally(import_effect.FiberRef.currentLogLevel, logLevel)(result);
|
|
245
|
+
}
|
|
246
|
+
if (sinks && sinks.length > 0) {
|
|
247
|
+
result = import_effect.Effect.locally(
|
|
248
|
+
Logix.Debug.internal.currentDebugSinks,
|
|
249
|
+
sinks
|
|
250
|
+
)(result);
|
|
251
|
+
}
|
|
252
|
+
return result;
|
|
253
|
+
};
|
|
254
|
+
const adapted = {
|
|
255
|
+
...runtime,
|
|
256
|
+
runFork: (effect, options) => runtime.runFork(applyLoggers(applyContexts(effect)), options),
|
|
257
|
+
runPromise: (effect, options) => runtime.runPromise(applyLoggers(applyContexts(effect)), options),
|
|
258
|
+
runPromiseExit: (effect, options) => runtime.runPromiseExit(applyLoggers(applyContexts(effect)), options),
|
|
259
|
+
runSync: (effect) => runtime.runSync(applyLoggers(applyContexts(effect))),
|
|
260
|
+
runSyncExit: (effect) => runtime.runSyncExit(applyLoggers(applyContexts(effect))),
|
|
261
|
+
runCallback: (effect, options) => runtime.runCallback(applyLoggers(applyContexts(effect)), options)
|
|
262
|
+
};
|
|
263
|
+
return adapted;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// src/internal/provider/errors.ts
|
|
267
|
+
var RuntimeProviderNotFoundError = class extends Error {
|
|
268
|
+
constructor(hookName) {
|
|
269
|
+
super(
|
|
270
|
+
`[${hookName}] RuntimeProvider not found.
|
|
271
|
+
|
|
272
|
+
Fix:
|
|
273
|
+
- Wrap your app (or the calling component subtree) with <RuntimeProvider runtime={runtime}>.
|
|
274
|
+
- If using nested providers, ensure an ancestor RuntimeProvider provides \`runtime\`.
|
|
275
|
+
- If you intended to call this hook outside React, use @logixjs/core directly.
|
|
276
|
+
`
|
|
277
|
+
);
|
|
278
|
+
this.name = "RuntimeProviderNotFoundError";
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// src/internal/hooks/useRuntime.ts
|
|
283
|
+
function useRuntime(options) {
|
|
284
|
+
const context = (0, import_react3.useContext)(RuntimeContext);
|
|
285
|
+
if (!context) {
|
|
286
|
+
throw new RuntimeProviderNotFoundError("useRuntime");
|
|
287
|
+
}
|
|
288
|
+
const mergedLayerCacheRef = (0, import_react3.useRef)(null);
|
|
289
|
+
const mergedLayer = (0, import_react3.useMemo)(() => {
|
|
290
|
+
if (!options) {
|
|
291
|
+
return void 0;
|
|
292
|
+
}
|
|
293
|
+
const { layer, layers } = options;
|
|
294
|
+
const hasLayersArray = Array.isArray(layers) && layers.length > 0;
|
|
295
|
+
if (!layer && !hasLayersArray) {
|
|
296
|
+
return void 0;
|
|
297
|
+
}
|
|
298
|
+
if (hasLayersArray) {
|
|
299
|
+
const all = layer ? [layer, ...layers] : layers;
|
|
300
|
+
const cached = mergedLayerCacheRef.current;
|
|
301
|
+
const shallowEqual = cached && cached.layers.length === all.length && cached.layers.every((item, idx) => item === all[idx]);
|
|
302
|
+
if (shallowEqual) {
|
|
303
|
+
return cached.merged;
|
|
304
|
+
}
|
|
305
|
+
const merged = import_effect2.Layer.mergeAll(...all);
|
|
306
|
+
mergedLayerCacheRef.current = { layers: all, merged };
|
|
307
|
+
return merged;
|
|
308
|
+
}
|
|
309
|
+
return layer;
|
|
310
|
+
}, [options?.layer, options?.layers]);
|
|
311
|
+
const lastLayersRef = (0, import_react3.useRef)(null);
|
|
312
|
+
const shallowEqualLayers = (a, b) => !!a && !!b && a.length === b.length && a.every((item, idx) => item === b[idx]);
|
|
313
|
+
(0, import_react3.useEffect)(() => {
|
|
314
|
+
if (!(0, import_Env.isDevEnv)()) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (options?.layers && lastLayersRef.current && lastLayersRef.current !== options.layers && !shallowEqualLayers(lastLayersRef.current, options.layers)) {
|
|
318
|
+
console.warn(
|
|
319
|
+
"[RuntimeProvider] useRuntime received a new layers reference. Memoize the layers array with useMemo to avoid rebuilding Layers on every render (performance jitter)."
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
lastLayersRef.current = options?.layers ?? null;
|
|
323
|
+
}, [options?.layers]);
|
|
324
|
+
const { binding } = useLayerBinding(context.runtime, mergedLayer, !!mergedLayer);
|
|
325
|
+
return (0, import_react3.useMemo)(() => {
|
|
326
|
+
if (!binding) {
|
|
327
|
+
return context.runtime;
|
|
328
|
+
}
|
|
329
|
+
return createRuntimeAdapter(
|
|
330
|
+
context.runtime,
|
|
331
|
+
[binding.context],
|
|
332
|
+
[binding.scope],
|
|
333
|
+
[binding.loggers],
|
|
334
|
+
[binding.logLevel],
|
|
335
|
+
[binding.debugSinks]
|
|
336
|
+
);
|
|
337
|
+
}, [context.runtime, binding]);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// src/internal/store/ModuleRef.ts
|
|
341
|
+
var isModuleRef = (value) => typeof value === "object" && value !== null && "runtime" in value && "actions" in value && "dispatch" in value;
|
|
342
|
+
var makeModuleActions = (dispatch) => {
|
|
343
|
+
const cache = /* @__PURE__ */ new Map();
|
|
344
|
+
const api = new Proxy(
|
|
345
|
+
{},
|
|
346
|
+
{
|
|
347
|
+
get: (_target, prop) => {
|
|
348
|
+
if (cache.has(prop)) {
|
|
349
|
+
return cache.get(prop);
|
|
350
|
+
}
|
|
351
|
+
if (prop === "dispatch") {
|
|
352
|
+
cache.set(prop, dispatch);
|
|
353
|
+
return dispatch;
|
|
354
|
+
}
|
|
355
|
+
if (prop === "then" || typeof prop !== "string") {
|
|
356
|
+
return void 0;
|
|
357
|
+
}
|
|
358
|
+
const fn = (...args) => {
|
|
359
|
+
const payload = args[0];
|
|
360
|
+
dispatch({ _tag: prop, payload });
|
|
361
|
+
};
|
|
362
|
+
cache.set(prop, fn);
|
|
363
|
+
return fn;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
);
|
|
367
|
+
return api;
|
|
368
|
+
};
|
|
369
|
+
function makeModuleDispatchers(dispatch, tokens) {
|
|
370
|
+
const cache = /* @__PURE__ */ new Map();
|
|
371
|
+
if (tokens) {
|
|
372
|
+
const out = {};
|
|
373
|
+
for (const [key, token] of Object.entries(tokens)) {
|
|
374
|
+
const fn = Object.assign(
|
|
375
|
+
((...args) => {
|
|
376
|
+
const action = token(...args);
|
|
377
|
+
dispatch(action);
|
|
378
|
+
return action;
|
|
379
|
+
}),
|
|
380
|
+
token
|
|
381
|
+
);
|
|
382
|
+
out[key] = fn;
|
|
383
|
+
}
|
|
384
|
+
return out;
|
|
385
|
+
}
|
|
386
|
+
const api = new Proxy(
|
|
387
|
+
{},
|
|
388
|
+
{
|
|
389
|
+
get: (_target, prop) => {
|
|
390
|
+
if (cache.has(prop)) {
|
|
391
|
+
return cache.get(prop);
|
|
392
|
+
}
|
|
393
|
+
if (prop === "then" || prop === "dispatch" || typeof prop !== "string") {
|
|
394
|
+
return void 0;
|
|
395
|
+
}
|
|
396
|
+
const fn = (...args) => {
|
|
397
|
+
const payload = args[0];
|
|
398
|
+
const action = { _tag: prop, payload };
|
|
399
|
+
dispatch(action);
|
|
400
|
+
return action;
|
|
401
|
+
};
|
|
402
|
+
cache.set(prop, fn);
|
|
403
|
+
return fn;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
return api;
|
|
408
|
+
}
|
|
409
|
+
var HANDLE_EXTEND = /* @__PURE__ */ Symbol.for("logix.module.handle.extend");
|
|
410
|
+
var isObjectLike = (value) => typeof value === "object" && value !== null || typeof value === "function";
|
|
411
|
+
var applyHandleExtend = (tag, runtime, base) => {
|
|
412
|
+
if (!isObjectLike(tag)) {
|
|
413
|
+
return base;
|
|
414
|
+
}
|
|
415
|
+
const extend = tag[HANDLE_EXTEND];
|
|
416
|
+
if (typeof extend !== "function") {
|
|
417
|
+
return base;
|
|
418
|
+
}
|
|
419
|
+
const next = extend(
|
|
420
|
+
runtime,
|
|
421
|
+
base
|
|
422
|
+
);
|
|
423
|
+
if (!next || typeof next !== "object") {
|
|
424
|
+
return base;
|
|
425
|
+
}
|
|
426
|
+
return { ...base, ...next };
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
// src/internal/store/ModuleCache.ts
|
|
430
|
+
var Logix3 = __toESM(require("@logixjs/core"), 1);
|
|
431
|
+
var import_effect4 = require("effect");
|
|
432
|
+
|
|
433
|
+
// src/internal/store/perfWorkloads.ts
|
|
434
|
+
var Logix2 = __toESM(require("@logixjs/core"), 1);
|
|
435
|
+
var import_effect3 = require("effect");
|
|
436
|
+
var PerfCounterStateSchema = import_effect3.Schema.Struct({
|
|
437
|
+
value: import_effect3.Schema.Number
|
|
438
|
+
});
|
|
439
|
+
var PerfCounterActions = {
|
|
440
|
+
inc: import_effect3.Schema.Void
|
|
441
|
+
};
|
|
442
|
+
var PerfListScopeRowSchema = import_effect3.Schema.Struct({
|
|
443
|
+
id: import_effect3.Schema.String,
|
|
444
|
+
warehouseId: import_effect3.Schema.String
|
|
445
|
+
});
|
|
446
|
+
var PerfListScopeStateSchema = import_effect3.Schema.Struct({
|
|
447
|
+
items: import_effect3.Schema.Array(PerfListScopeRowSchema),
|
|
448
|
+
digest: import_effect3.Schema.String,
|
|
449
|
+
errors: import_effect3.Schema.Any
|
|
450
|
+
});
|
|
451
|
+
var GLOBAL_YIELD_BUDGET_MEMORY_KEY = "__LOGIX_REACT_YIELD_BUDGET_MEMORY__";
|
|
452
|
+
var getGlobalYieldBudgetMemory = () => {
|
|
453
|
+
const root = globalThis;
|
|
454
|
+
const existing = root[GLOBAL_YIELD_BUDGET_MEMORY_KEY];
|
|
455
|
+
if (existing && existing.byRuntime instanceof WeakMap) {
|
|
456
|
+
return existing;
|
|
457
|
+
}
|
|
458
|
+
const created = { byRuntime: /* @__PURE__ */ new WeakMap() };
|
|
459
|
+
root[GLOBAL_YIELD_BUDGET_MEMORY_KEY] = created;
|
|
460
|
+
return created;
|
|
461
|
+
};
|
|
462
|
+
var getStatsMapForRuntime = (runtime) => {
|
|
463
|
+
const global = getGlobalYieldBudgetMemory();
|
|
464
|
+
const cached = global.byRuntime.get(runtime);
|
|
465
|
+
if (cached) return cached;
|
|
466
|
+
const created = /* @__PURE__ */ new Map();
|
|
467
|
+
global.byRuntime.set(runtime, created);
|
|
468
|
+
return created;
|
|
469
|
+
};
|
|
470
|
+
var quantile = (sorted, q) => {
|
|
471
|
+
if (sorted.length === 0) return Number.NaN;
|
|
472
|
+
const clamped = Math.min(1, Math.max(0, q));
|
|
473
|
+
const idx = Math.floor(clamped * (sorted.length - 1));
|
|
474
|
+
return sorted[idx];
|
|
475
|
+
};
|
|
476
|
+
var p95 = (samplesMs) => {
|
|
477
|
+
if (samplesMs.length === 0) return Number.NaN;
|
|
478
|
+
const sorted = samplesMs.slice().sort((a, b) => a - b);
|
|
479
|
+
return quantile(sorted, 0.95);
|
|
480
|
+
};
|
|
481
|
+
var YieldBudgetMemory = {
|
|
482
|
+
shouldYield(args) {
|
|
483
|
+
const budgetMs = args.policy?.onlyWhenOverBudgetMs;
|
|
484
|
+
if (budgetMs === void 0) {
|
|
485
|
+
return { shouldYield: true, reason: "budgetDisabled", p95Ms: void 0 };
|
|
486
|
+
}
|
|
487
|
+
const byKey = getStatsMapForRuntime(args.runtime);
|
|
488
|
+
const stats = byKey.get(args.workloadKey) ?? { seen: false, samplesMs: [] };
|
|
489
|
+
if (!byKey.has(args.workloadKey)) {
|
|
490
|
+
byKey.set(args.workloadKey, stats);
|
|
491
|
+
}
|
|
492
|
+
if (!stats.seen) {
|
|
493
|
+
stats.seen = true;
|
|
494
|
+
return { shouldYield: true, reason: "firstRun", p95Ms: void 0 };
|
|
495
|
+
}
|
|
496
|
+
if (stats.samplesMs.length === 0) {
|
|
497
|
+
return { shouldYield: true, reason: "insufficientSamples", p95Ms: void 0 };
|
|
498
|
+
}
|
|
499
|
+
const p95Ms = p95(stats.samplesMs);
|
|
500
|
+
if (!Number.isFinite(p95Ms)) {
|
|
501
|
+
return { shouldYield: true, reason: "insufficientSamples", p95Ms: void 0 };
|
|
502
|
+
}
|
|
503
|
+
return p95Ms > budgetMs ? { shouldYield: true, reason: "overBudget", p95Ms } : { shouldYield: false, reason: "underBudget", p95Ms };
|
|
504
|
+
},
|
|
505
|
+
record(args) {
|
|
506
|
+
if (!Number.isFinite(args.durationMs) || args.durationMs < 0) return;
|
|
507
|
+
const byKey = getStatsMapForRuntime(args.runtime);
|
|
508
|
+
const stats = byKey.get(args.workloadKey) ?? { seen: true, samplesMs: [] };
|
|
509
|
+
if (!byKey.has(args.workloadKey)) {
|
|
510
|
+
byKey.set(args.workloadKey, stats);
|
|
511
|
+
}
|
|
512
|
+
stats.samplesMs.push(args.durationMs);
|
|
513
|
+
if (stats.samplesMs.length > 20) {
|
|
514
|
+
stats.samplesMs.shift();
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
// src/internal/store/ModuleCache.ts
|
|
520
|
+
var RUNTIME_CACHE = /* @__PURE__ */ new WeakMap();
|
|
521
|
+
var DEFAULT_GC_DELAY_MS = 500;
|
|
522
|
+
var ERROR_GC_DELAY_MS = 500;
|
|
523
|
+
var DEFAULT_RENDER_SYNC_BLOCKING_WARN_THRESHOLD_MS = 5;
|
|
524
|
+
var toErrorString2 = (error) => {
|
|
525
|
+
if (error instanceof Error) {
|
|
526
|
+
return error.stack ?? error.message;
|
|
527
|
+
}
|
|
528
|
+
return String(error);
|
|
529
|
+
};
|
|
530
|
+
var seenBestEffortFailures = /* @__PURE__ */ new Set();
|
|
531
|
+
var debugBestEffortFailure = (label, error) => {
|
|
532
|
+
if (!(0, import_Env.isDevEnv)()) return;
|
|
533
|
+
const message = toErrorString2(error);
|
|
534
|
+
if (message.includes("ManagedRuntime disposed")) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const key = `${label}
|
|
538
|
+
${message}`;
|
|
539
|
+
if (seenBestEffortFailures.has(key)) return;
|
|
540
|
+
seenBestEffortFailures.add(key);
|
|
541
|
+
console.debug(label, message);
|
|
542
|
+
};
|
|
543
|
+
var causeToUnknown = (cause) => {
|
|
544
|
+
const failure = import_effect4.Option.getOrUndefined(import_effect4.Cause.failureOption(cause));
|
|
545
|
+
if (failure !== void 0) return failure;
|
|
546
|
+
const defect = import_effect4.Option.getOrUndefined(import_effect4.Cause.dieOption(cause));
|
|
547
|
+
if (defect !== void 0) return defect;
|
|
548
|
+
return cause;
|
|
549
|
+
};
|
|
550
|
+
var yieldEffect = (strategy) => {
|
|
551
|
+
switch (strategy) {
|
|
552
|
+
case "none":
|
|
553
|
+
return import_effect4.Effect.void;
|
|
554
|
+
case "microtask":
|
|
555
|
+
return import_effect4.Effect.yieldNow();
|
|
556
|
+
case "macrotask":
|
|
557
|
+
return import_effect4.Effect.promise(
|
|
558
|
+
() => new Promise((resolve) => {
|
|
559
|
+
setTimeout(resolve, 0);
|
|
560
|
+
})
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
var decideYieldStrategy = (runtime, workloadKey, policy) => {
|
|
565
|
+
const baseStrategy = policy?.strategy ?? "microtask";
|
|
566
|
+
if (baseStrategy === "none") {
|
|
567
|
+
return { strategy: "none", reason: "disabled" };
|
|
568
|
+
}
|
|
569
|
+
const budgetMs = policy?.onlyWhenOverBudgetMs;
|
|
570
|
+
if (budgetMs === void 0) {
|
|
571
|
+
return { strategy: baseStrategy };
|
|
572
|
+
}
|
|
573
|
+
const decision = YieldBudgetMemory.shouldYield({ runtime, workloadKey, policy });
|
|
574
|
+
return decision.shouldYield ? { strategy: baseStrategy, reason: decision.reason, p95Ms: decision.p95Ms } : { strategy: "none", reason: decision.reason, p95Ms: decision.p95Ms };
|
|
575
|
+
};
|
|
576
|
+
var warnedSyncBlockingKeys = /* @__PURE__ */ new Set();
|
|
577
|
+
var ModuleCache = class {
|
|
578
|
+
constructor(runtime, gcDelayMs = DEFAULT_GC_DELAY_MS) {
|
|
579
|
+
this.runtime = runtime;
|
|
580
|
+
this.gcDelayMs = gcDelayMs;
|
|
581
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
582
|
+
}
|
|
583
|
+
scheduleGC(key, entry) {
|
|
584
|
+
if (entry.gcTimeout) {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const delay = entry.gcTime;
|
|
588
|
+
if (!Number.isFinite(delay)) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
const timeoutMs = delay <= 0 ? 0 : delay;
|
|
592
|
+
entry.gcTimeout = setTimeout(() => {
|
|
593
|
+
const current = this.entries.get(key);
|
|
594
|
+
if (!current || current !== entry) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
current.gcTimeout = void 0;
|
|
598
|
+
if (current.refCount > 0 || current.preloadRefCount > 0) {
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
if (current.status === "pending") {
|
|
602
|
+
this.scheduleGC(key, current);
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
void this.runtime.runPromise(import_effect4.Scope.close(current.scope, import_effect4.Exit.void)).catch((error) => {
|
|
606
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", error);
|
|
607
|
+
});
|
|
608
|
+
void this.runtime.runPromise(
|
|
609
|
+
Logix3.Debug.record({
|
|
610
|
+
type: "trace:react.module-instance",
|
|
611
|
+
moduleId: current.ownerId,
|
|
612
|
+
instanceId: current.value?.instanceId,
|
|
613
|
+
data: {
|
|
614
|
+
event: "gc",
|
|
615
|
+
key
|
|
616
|
+
}
|
|
617
|
+
})
|
|
618
|
+
).catch((error) => {
|
|
619
|
+
debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
|
|
620
|
+
});
|
|
621
|
+
this.entries.delete(key);
|
|
622
|
+
}, timeoutMs);
|
|
623
|
+
}
|
|
624
|
+
read(key, factory, gcTime, ownerId, options) {
|
|
625
|
+
const existing = this.entries.get(key);
|
|
626
|
+
if (existing) {
|
|
627
|
+
if ((0, import_Env.isDevEnv)() && existing.ownerId !== void 0 && ownerId !== void 0 && existing.ownerId !== ownerId) {
|
|
628
|
+
console.error(
|
|
629
|
+
"[ModuleCache.read] resource key ownership mismatch:",
|
|
630
|
+
`key="${key}" previously owned by "${existing.ownerId}",`,
|
|
631
|
+
`but now requested by "${ownerId}".`
|
|
632
|
+
);
|
|
633
|
+
throw new Error(
|
|
634
|
+
`[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.`
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
if (existing.status === "pending") {
|
|
638
|
+
throw existing.promise;
|
|
639
|
+
}
|
|
640
|
+
if (existing.status === "error") {
|
|
641
|
+
throw existing.error;
|
|
642
|
+
}
|
|
643
|
+
return existing.value;
|
|
644
|
+
}
|
|
645
|
+
const scope = import_effect4.Effect.runSync(import_effect4.Scope.make());
|
|
646
|
+
const workloadKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`;
|
|
647
|
+
const yieldDecision = decideYieldStrategy(this.runtime, workloadKey, options?.yield);
|
|
648
|
+
const entry = {
|
|
649
|
+
scope,
|
|
650
|
+
status: "pending",
|
|
651
|
+
// Placeholder; will be replaced immediately with the real Promise.
|
|
652
|
+
promise: Promise.resolve(null),
|
|
653
|
+
refCount: 0,
|
|
654
|
+
preloadRefCount: 0,
|
|
655
|
+
gcTime: gcTime ?? this.gcDelayMs,
|
|
656
|
+
ownerId,
|
|
657
|
+
createdBy: "read",
|
|
658
|
+
workloadKey,
|
|
659
|
+
yieldStrategy: yieldDecision.strategy
|
|
660
|
+
};
|
|
661
|
+
this.scheduleGC(key, entry);
|
|
662
|
+
const startedAt = performance.now();
|
|
663
|
+
const buildEffect = yieldEffect(yieldDecision.strategy).pipe(import_effect4.Effect.zipRight(factory(scope)));
|
|
664
|
+
const fiber = this.runtime.runFork(buildEffect);
|
|
665
|
+
entry.fiber = fiber;
|
|
666
|
+
const promise = this.runtime.runPromise(import_effect4.Fiber.await(fiber)).then((exit) => {
|
|
667
|
+
if (import_effect4.Exit.isSuccess(exit)) return exit.value;
|
|
668
|
+
throw causeToUnknown(exit.cause);
|
|
669
|
+
});
|
|
670
|
+
promise.then((value) => {
|
|
671
|
+
entry.status = "success";
|
|
672
|
+
entry.value = value;
|
|
673
|
+
const durationMs = performance.now() - startedAt;
|
|
674
|
+
YieldBudgetMemory.record({ runtime: this.runtime, workloadKey, durationMs });
|
|
675
|
+
if ((0, import_Env.isDevEnv)() || Logix3.Debug.isDevtoolsEnabled()) {
|
|
676
|
+
void this.runtime.runPromise(
|
|
677
|
+
Logix3.Debug.record({
|
|
678
|
+
type: "trace:react.module.init",
|
|
679
|
+
moduleId: ownerId,
|
|
680
|
+
instanceId: value.instanceId,
|
|
681
|
+
data: {
|
|
682
|
+
mode: "suspend",
|
|
683
|
+
key,
|
|
684
|
+
durationMs: Math.round(durationMs * 100) / 100,
|
|
685
|
+
yieldStrategy: yieldDecision.strategy,
|
|
686
|
+
yieldReason: yieldDecision.reason,
|
|
687
|
+
yieldP95Ms: yieldDecision.p95Ms
|
|
688
|
+
}
|
|
689
|
+
})
|
|
690
|
+
).catch((error) => {
|
|
691
|
+
debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
|
|
692
|
+
});
|
|
693
|
+
void this.runtime.runPromise(
|
|
694
|
+
Logix3.Debug.record({
|
|
695
|
+
type: "trace:react.module-instance",
|
|
696
|
+
moduleId: ownerId,
|
|
697
|
+
instanceId: value.instanceId,
|
|
698
|
+
data: {
|
|
699
|
+
event: "attach",
|
|
700
|
+
key,
|
|
701
|
+
mode: "suspend",
|
|
702
|
+
gcTime: entry.gcTime
|
|
703
|
+
}
|
|
704
|
+
})
|
|
705
|
+
).catch((error) => {
|
|
706
|
+
debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
return value;
|
|
710
|
+
}).catch((error) => {
|
|
711
|
+
entry.status = "error";
|
|
712
|
+
entry.error = error;
|
|
713
|
+
entry.gcTime = ERROR_GC_DELAY_MS;
|
|
714
|
+
if (entry.gcTimeout) {
|
|
715
|
+
clearTimeout(entry.gcTimeout);
|
|
716
|
+
entry.gcTimeout = void 0;
|
|
717
|
+
}
|
|
718
|
+
this.scheduleGC(key, entry);
|
|
719
|
+
YieldBudgetMemory.record({
|
|
720
|
+
runtime: this.runtime,
|
|
721
|
+
workloadKey,
|
|
722
|
+
durationMs: performance.now() - startedAt
|
|
723
|
+
});
|
|
724
|
+
void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
|
|
725
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
|
|
726
|
+
});
|
|
727
|
+
throw error;
|
|
728
|
+
});
|
|
729
|
+
this.entries.set(key, entry);
|
|
730
|
+
entry.promise = promise;
|
|
731
|
+
throw promise;
|
|
732
|
+
}
|
|
733
|
+
readSync(key, factory, gcTime, ownerId, options) {
|
|
734
|
+
const existing = this.entries.get(key);
|
|
735
|
+
if (existing) {
|
|
736
|
+
if ((0, import_Env.isDevEnv)() && existing.ownerId !== void 0 && ownerId !== void 0 && existing.ownerId !== ownerId) {
|
|
737
|
+
console.error(
|
|
738
|
+
"[ModuleCache.readSync] resource key ownership mismatch:",
|
|
739
|
+
`key="${key}" previously owned by "${existing.ownerId}",`,
|
|
740
|
+
`but now requested by "${ownerId}".`
|
|
741
|
+
);
|
|
742
|
+
throw new Error(
|
|
743
|
+
`[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.`
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
if (existing.status === "error") {
|
|
747
|
+
throw existing.error;
|
|
748
|
+
}
|
|
749
|
+
if (existing.status === "pending") {
|
|
750
|
+
throw new Error(
|
|
751
|
+
`[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.`
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
return existing.value;
|
|
755
|
+
}
|
|
756
|
+
const scope = this.runtime.runSync(import_effect4.Scope.make());
|
|
757
|
+
const startedAt = performance.now();
|
|
758
|
+
try {
|
|
759
|
+
const value = this.runtime.runSync(factory(scope));
|
|
760
|
+
const durationMs = performance.now() - startedAt;
|
|
761
|
+
const entry = {
|
|
762
|
+
scope,
|
|
763
|
+
status: "success",
|
|
764
|
+
promise: Promise.resolve(value),
|
|
765
|
+
value,
|
|
766
|
+
refCount: 0,
|
|
767
|
+
preloadRefCount: 0,
|
|
768
|
+
gcTime: gcTime ?? this.gcDelayMs,
|
|
769
|
+
ownerId,
|
|
770
|
+
createdBy: "read",
|
|
771
|
+
workloadKey: `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`,
|
|
772
|
+
yieldStrategy: "none"
|
|
773
|
+
};
|
|
774
|
+
this.scheduleGC(key, entry);
|
|
775
|
+
this.entries.set(key, entry);
|
|
776
|
+
if ((0, import_Env.isDevEnv)()) {
|
|
777
|
+
const threshold = options?.warnSyncBlockingThresholdMs ?? DEFAULT_RENDER_SYNC_BLOCKING_WARN_THRESHOLD_MS;
|
|
778
|
+
if (threshold > 0 && durationMs > threshold) {
|
|
779
|
+
const dedupeKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}::${key}`;
|
|
780
|
+
if (!warnedSyncBlockingKeys.has(dedupeKey)) {
|
|
781
|
+
warnedSyncBlockingKeys.add(dedupeKey);
|
|
782
|
+
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';
|
|
783
|
+
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>';
|
|
784
|
+
const docs = "Docs: apps/docs/content/docs/guide/essentials/react-integration.md";
|
|
785
|
+
console.warn(
|
|
786
|
+
"[Logix][React] Render-phase sync blocking detected",
|
|
787
|
+
`(${Math.round(durationMs * 100) / 100}ms > ${threshold}ms)`,
|
|
788
|
+
"\n",
|
|
789
|
+
`entrypoint=${options?.entrypoint ?? "unknown"}`,
|
|
790
|
+
"\n",
|
|
791
|
+
`ownerId=${ownerId ?? "unknown"}`,
|
|
792
|
+
"\n",
|
|
793
|
+
`key=${key}`,
|
|
794
|
+
"\n",
|
|
795
|
+
hint,
|
|
796
|
+
"\n",
|
|
797
|
+
example,
|
|
798
|
+
"\n",
|
|
799
|
+
docs
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
if ((0, import_Env.isDevEnv)() || Logix3.Debug.isDevtoolsEnabled()) {
|
|
805
|
+
void this.runtime.runPromise(
|
|
806
|
+
Logix3.Debug.record({
|
|
807
|
+
type: "trace:react.module.init",
|
|
808
|
+
moduleId: ownerId,
|
|
809
|
+
instanceId: value.instanceId,
|
|
810
|
+
data: {
|
|
811
|
+
mode: "sync",
|
|
812
|
+
key,
|
|
813
|
+
durationMs: Math.round(durationMs * 100) / 100,
|
|
814
|
+
yieldStrategy: "none"
|
|
815
|
+
}
|
|
816
|
+
})
|
|
817
|
+
).catch((error) => {
|
|
818
|
+
debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
|
|
819
|
+
});
|
|
820
|
+
void this.runtime.runPromise(
|
|
821
|
+
Logix3.Debug.record({
|
|
822
|
+
type: "trace:react.module-instance",
|
|
823
|
+
moduleId: ownerId,
|
|
824
|
+
instanceId: value.instanceId,
|
|
825
|
+
data: {
|
|
826
|
+
event: "attach",
|
|
827
|
+
key,
|
|
828
|
+
mode: "sync",
|
|
829
|
+
gcTime: entry.gcTime
|
|
830
|
+
}
|
|
831
|
+
})
|
|
832
|
+
).catch((error) => {
|
|
833
|
+
debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
return value;
|
|
837
|
+
} catch (error) {
|
|
838
|
+
void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
|
|
839
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
|
|
840
|
+
});
|
|
841
|
+
const entry = {
|
|
842
|
+
scope,
|
|
843
|
+
status: "error",
|
|
844
|
+
promise: Promise.reject(error),
|
|
845
|
+
error,
|
|
846
|
+
refCount: 0,
|
|
847
|
+
preloadRefCount: 0,
|
|
848
|
+
gcTime: ERROR_GC_DELAY_MS,
|
|
849
|
+
ownerId,
|
|
850
|
+
createdBy: "read",
|
|
851
|
+
workloadKey: `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`,
|
|
852
|
+
yieldStrategy: "none"
|
|
853
|
+
};
|
|
854
|
+
this.scheduleGC(key, entry);
|
|
855
|
+
this.entries.set(key, entry);
|
|
856
|
+
throw error;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
preload(key, factory, options) {
|
|
860
|
+
const existing = this.entries.get(key);
|
|
861
|
+
if (existing) {
|
|
862
|
+
if (existing.status === "success") {
|
|
863
|
+
existing.preloadRefCount += 1;
|
|
864
|
+
return {
|
|
865
|
+
promise: Promise.resolve(existing.value),
|
|
866
|
+
cancel: () => {
|
|
867
|
+
this.cancelPreload(key, existing);
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
if (existing.status === "error") {
|
|
872
|
+
return { promise: Promise.reject(existing.error), cancel: () => {
|
|
873
|
+
} };
|
|
874
|
+
}
|
|
875
|
+
existing.preloadRefCount += 1;
|
|
876
|
+
return {
|
|
877
|
+
promise: existing.promise,
|
|
878
|
+
cancel: () => {
|
|
879
|
+
this.cancelPreload(key, existing);
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
const scope = import_effect4.Effect.runSync(import_effect4.Scope.make());
|
|
884
|
+
const ownerId = options?.ownerId;
|
|
885
|
+
const gcTime = options?.gcTime ?? this.gcDelayMs;
|
|
886
|
+
const workloadKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`;
|
|
887
|
+
const yieldDecision = decideYieldStrategy(this.runtime, workloadKey, options?.yield);
|
|
888
|
+
const entry = {
|
|
889
|
+
scope,
|
|
890
|
+
status: "pending",
|
|
891
|
+
promise: Promise.resolve(null),
|
|
892
|
+
refCount: 0,
|
|
893
|
+
preloadRefCount: 1,
|
|
894
|
+
gcTime,
|
|
895
|
+
ownerId,
|
|
896
|
+
createdBy: "preload",
|
|
897
|
+
workloadKey,
|
|
898
|
+
yieldStrategy: yieldDecision.strategy
|
|
899
|
+
};
|
|
900
|
+
this.scheduleGC(key, entry);
|
|
901
|
+
this.entries.set(key, entry);
|
|
902
|
+
const startedAt = performance.now();
|
|
903
|
+
const buildEffect = yieldEffect(yieldDecision.strategy).pipe(import_effect4.Effect.zipRight(factory(scope)));
|
|
904
|
+
const fiber = this.runtime.runFork(buildEffect);
|
|
905
|
+
entry.fiber = fiber;
|
|
906
|
+
const promise = this.runtime.runPromise(import_effect4.Fiber.await(fiber)).then((exit) => {
|
|
907
|
+
if (import_effect4.Exit.isSuccess(exit)) return exit.value;
|
|
908
|
+
throw causeToUnknown(exit.cause);
|
|
909
|
+
});
|
|
910
|
+
entry.promise = promise;
|
|
911
|
+
void promise.then((value) => {
|
|
912
|
+
entry.status = "success";
|
|
913
|
+
entry.value = value;
|
|
914
|
+
YieldBudgetMemory.record({
|
|
915
|
+
runtime: this.runtime,
|
|
916
|
+
workloadKey,
|
|
917
|
+
durationMs: performance.now() - startedAt
|
|
918
|
+
});
|
|
919
|
+
}).catch((error) => {
|
|
920
|
+
entry.status = "error";
|
|
921
|
+
entry.error = error;
|
|
922
|
+
entry.gcTime = ERROR_GC_DELAY_MS;
|
|
923
|
+
if (entry.gcTimeout) {
|
|
924
|
+
clearTimeout(entry.gcTimeout);
|
|
925
|
+
entry.gcTimeout = void 0;
|
|
926
|
+
}
|
|
927
|
+
this.scheduleGC(key, entry);
|
|
928
|
+
YieldBudgetMemory.record({
|
|
929
|
+
runtime: this.runtime,
|
|
930
|
+
workloadKey,
|
|
931
|
+
durationMs: performance.now() - startedAt
|
|
932
|
+
});
|
|
933
|
+
void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
|
|
934
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
|
|
935
|
+
});
|
|
936
|
+
});
|
|
937
|
+
return {
|
|
938
|
+
promise,
|
|
939
|
+
cancel: () => {
|
|
940
|
+
this.cancelPreload(key, entry);
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
cancelPreload(key, entry) {
|
|
945
|
+
const current = this.entries.get(key);
|
|
946
|
+
if (!current || current !== entry) {
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
entry.preloadRefCount = Math.max(0, entry.preloadRefCount - 1);
|
|
950
|
+
if (entry.preloadRefCount > 0) {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
if (entry.refCount > 0) {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
if (entry.status === "pending") {
|
|
957
|
+
if (entry.createdBy !== "preload") {
|
|
958
|
+
this.scheduleGC(key, entry);
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
const running = entry.fiber;
|
|
962
|
+
entry.fiber = void 0;
|
|
963
|
+
this.entries.delete(key);
|
|
964
|
+
if (running) {
|
|
965
|
+
this.runtime.runFork(import_effect4.Fiber.interrupt(running));
|
|
966
|
+
}
|
|
967
|
+
void this.runtime.runPromise(import_effect4.Scope.close(entry.scope, import_effect4.Exit.void)).catch((closeError) => {
|
|
968
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
|
|
969
|
+
});
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
if (entry.gcTimeout) {
|
|
973
|
+
clearTimeout(entry.gcTimeout);
|
|
974
|
+
entry.gcTimeout = void 0;
|
|
975
|
+
}
|
|
976
|
+
this.scheduleGC(key, entry);
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* Declares ownership of a resource after component commit.
|
|
980
|
+
* The returned function releases the reference during cleanup.
|
|
981
|
+
*/
|
|
982
|
+
retain(key) {
|
|
983
|
+
const entry = this.entries.get(key);
|
|
984
|
+
if (!entry) {
|
|
985
|
+
return () => {
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
entry.refCount += 1;
|
|
989
|
+
if (entry.gcTimeout) {
|
|
990
|
+
clearTimeout(entry.gcTimeout);
|
|
991
|
+
entry.gcTimeout = void 0;
|
|
992
|
+
}
|
|
993
|
+
return () => {
|
|
994
|
+
this.release(key);
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
release(key) {
|
|
998
|
+
const entry = this.entries.get(key);
|
|
999
|
+
if (!entry) {
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
entry.refCount -= 1;
|
|
1003
|
+
if (entry.refCount > 0) {
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
this.scheduleGC(key, entry);
|
|
1007
|
+
}
|
|
1008
|
+
dispose() {
|
|
1009
|
+
for (const [key, entry] of this.entries) {
|
|
1010
|
+
if (entry.gcTimeout) {
|
|
1011
|
+
clearTimeout(entry.gcTimeout);
|
|
1012
|
+
}
|
|
1013
|
+
void this.runtime.runPromise(import_effect4.Scope.close(entry.scope, import_effect4.Exit.void)).catch((error) => {
|
|
1014
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", error);
|
|
1015
|
+
});
|
|
1016
|
+
this.entries.delete(key);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
var getModuleCache = (runtime, config, version) => {
|
|
1021
|
+
const cached = RUNTIME_CACHE.get(runtime);
|
|
1022
|
+
if (cached && cached.version === version) {
|
|
1023
|
+
return cached.cache;
|
|
1024
|
+
}
|
|
1025
|
+
if (cached) {
|
|
1026
|
+
cached.cache.dispose();
|
|
1027
|
+
}
|
|
1028
|
+
const cache = new ModuleCache(runtime, config.gcTime);
|
|
1029
|
+
RUNTIME_CACHE.set(runtime, { version, cache });
|
|
1030
|
+
return cache;
|
|
1031
|
+
};
|
|
1032
|
+
var hashOf = (value) => {
|
|
1033
|
+
if (value === null) {
|
|
1034
|
+
return "null";
|
|
1035
|
+
}
|
|
1036
|
+
const type = typeof value;
|
|
1037
|
+
if (type === "string") {
|
|
1038
|
+
return `s:${value}`;
|
|
1039
|
+
}
|
|
1040
|
+
if (type === "number") {
|
|
1041
|
+
return `n:${value}`;
|
|
1042
|
+
}
|
|
1043
|
+
if (type === "boolean") {
|
|
1044
|
+
return `b:${value}`;
|
|
1045
|
+
}
|
|
1046
|
+
return `${type}:${Object.prototype.toString.call(value)}`;
|
|
1047
|
+
};
|
|
1048
|
+
var stableHash = (deps) => {
|
|
1049
|
+
if ((0, import_Env.isDevEnv)()) {
|
|
1050
|
+
const hasNonPrimitive = deps.some((value) => {
|
|
1051
|
+
if (value === null) return false;
|
|
1052
|
+
const type = typeof value;
|
|
1053
|
+
return type === "object" || type === "function";
|
|
1054
|
+
});
|
|
1055
|
+
if (hasNonPrimitive) {
|
|
1056
|
+
console.warn(
|
|
1057
|
+
"[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`."
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
return deps.map(hashOf).join("|");
|
|
1062
|
+
};
|
|
1063
|
+
|
|
1064
|
+
// src/internal/hooks/useModuleRuntime.ts
|
|
1065
|
+
var isModuleRuntime = (value) => typeof value === "object" && value !== null && "dispatch" in value && "getState" in value;
|
|
1066
|
+
function useModuleRuntime(handle) {
|
|
1067
|
+
const runtime = useRuntime();
|
|
1068
|
+
const runtimeContext = (0, import_react4.useContext)(RuntimeContext);
|
|
1069
|
+
if (!runtimeContext) {
|
|
1070
|
+
throw new RuntimeProviderNotFoundError("useModuleRuntime");
|
|
1071
|
+
}
|
|
1072
|
+
const cache = (0, import_react4.useMemo)(
|
|
1073
|
+
() => getModuleCache(runtimeContext.runtime, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion),
|
|
1074
|
+
[runtimeContext.runtime, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion]
|
|
1075
|
+
);
|
|
1076
|
+
const isTagHandle = !isModuleRef(handle) && !isModuleRuntime(handle);
|
|
1077
|
+
const resolved = (0, import_react4.useMemo)(() => {
|
|
1078
|
+
if (isModuleRef(handle)) {
|
|
1079
|
+
return handle.runtime;
|
|
1080
|
+
}
|
|
1081
|
+
if (isModuleRuntime(handle)) {
|
|
1082
|
+
return handle;
|
|
1083
|
+
}
|
|
1084
|
+
const tag = handle;
|
|
1085
|
+
const tokenId = tag.id ?? "ModuleTag";
|
|
1086
|
+
const preloadKey = runtimeContext.policy.preload?.keysByTagId.get(tokenId);
|
|
1087
|
+
const key = preloadKey ?? `tag:${tokenId}`;
|
|
1088
|
+
const mode = runtimeContext.policy.moduleTagMode;
|
|
1089
|
+
const factory = (scope) => tag.pipe(import_effect5.Scope.extend(scope));
|
|
1090
|
+
return mode === "suspend" ? cache.read(key, factory, void 0, tokenId, {
|
|
1091
|
+
entrypoint: "react.useModuleRuntime",
|
|
1092
|
+
policyMode: runtimeContext.policy.mode,
|
|
1093
|
+
yield: runtimeContext.policy.yield
|
|
1094
|
+
}) : cache.readSync(key, factory, void 0, tokenId, {
|
|
1095
|
+
entrypoint: "react.useModuleRuntime",
|
|
1096
|
+
policyMode: runtimeContext.policy.mode,
|
|
1097
|
+
warnSyncBlockingThresholdMs: 5
|
|
1098
|
+
});
|
|
1099
|
+
}, [cache, runtimeContext.policy, handle]);
|
|
1100
|
+
(0, import_react4.useEffect)(() => {
|
|
1101
|
+
if (!isTagHandle) {
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
if (!(0, import_Env.isDevEnv)() && !Logix4.Debug.isDevtoolsEnabled()) {
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
const tokenId = handle?.id ?? "ModuleTag";
|
|
1108
|
+
const effect = Logix4.Debug.record({
|
|
1109
|
+
type: "trace:react.moduleTag.resolve",
|
|
1110
|
+
moduleId: resolved.moduleId,
|
|
1111
|
+
instanceId: resolved.instanceId,
|
|
1112
|
+
data: {
|
|
1113
|
+
mode: runtimeContext.policy.moduleTagMode,
|
|
1114
|
+
tokenId,
|
|
1115
|
+
yieldStrategy: runtimeContext.policy.yield.strategy
|
|
1116
|
+
}
|
|
1117
|
+
});
|
|
1118
|
+
runtime.runFork(effect);
|
|
1119
|
+
}, [runtime, runtimeContext.policy, resolved, handle, isTagHandle]);
|
|
1120
|
+
return resolved;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// src/internal/hooks/useSelector.ts
|
|
1124
|
+
var import_react5 = require("react");
|
|
1125
|
+
var import_with_selector = require("use-sync-external-store/shim/with-selector");
|
|
1126
|
+
var Logix5 = __toESM(require("@logixjs/core"), 1);
|
|
1127
|
+
|
|
1128
|
+
// src/internal/store/ModuleRuntimeExternalStore.ts
|
|
1129
|
+
var import_effect6 = require("effect");
|
|
1130
|
+
var storesByRuntime = /* @__PURE__ */ new WeakMap();
|
|
1131
|
+
var getStoreMapForRuntime = (runtime) => {
|
|
1132
|
+
const cached = storesByRuntime.get(runtime);
|
|
1133
|
+
if (cached) return cached;
|
|
1134
|
+
const next = /* @__PURE__ */ new WeakMap();
|
|
1135
|
+
storesByRuntime.set(runtime, next);
|
|
1136
|
+
return next;
|
|
1137
|
+
};
|
|
1138
|
+
var getModuleRuntimeExternalStore = (runtime, moduleRuntime, options) => {
|
|
1139
|
+
const byModule = getStoreMapForRuntime(runtime);
|
|
1140
|
+
const cached = byModule.get(moduleRuntime);
|
|
1141
|
+
if (cached) {
|
|
1142
|
+
return cached;
|
|
1143
|
+
}
|
|
1144
|
+
let currentState;
|
|
1145
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1146
|
+
const lowPriorityDelayMs = options?.lowPriorityDelayMs ?? 16;
|
|
1147
|
+
const lowPriorityMaxDelayMs = options?.lowPriorityMaxDelayMs ?? 50;
|
|
1148
|
+
let notifyScheduled = false;
|
|
1149
|
+
let notifyScheduledLow = false;
|
|
1150
|
+
let lowTimeoutId;
|
|
1151
|
+
let lowMaxTimeoutId;
|
|
1152
|
+
let lowRafId;
|
|
1153
|
+
const cancelLow = () => {
|
|
1154
|
+
if (!notifyScheduledLow) return;
|
|
1155
|
+
notifyScheduledLow = false;
|
|
1156
|
+
if (lowTimeoutId != null) {
|
|
1157
|
+
clearTimeout(lowTimeoutId);
|
|
1158
|
+
lowTimeoutId = void 0;
|
|
1159
|
+
}
|
|
1160
|
+
if (lowMaxTimeoutId != null) {
|
|
1161
|
+
clearTimeout(lowMaxTimeoutId);
|
|
1162
|
+
lowMaxTimeoutId = void 0;
|
|
1163
|
+
}
|
|
1164
|
+
const cancel = globalThis.cancelAnimationFrame;
|
|
1165
|
+
if (cancel && typeof lowRafId === "number") {
|
|
1166
|
+
cancel(lowRafId);
|
|
1167
|
+
lowRafId = void 0;
|
|
1168
|
+
}
|
|
1169
|
+
};
|
|
1170
|
+
const flushNotify = () => {
|
|
1171
|
+
notifyScheduled = false;
|
|
1172
|
+
cancelLow();
|
|
1173
|
+
for (const listener of listeners) {
|
|
1174
|
+
listener();
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
const scheduleNotify = (priority) => {
|
|
1178
|
+
if (priority === "low") {
|
|
1179
|
+
if (notifyScheduled) return;
|
|
1180
|
+
if (notifyScheduledLow) return;
|
|
1181
|
+
notifyScheduledLow = true;
|
|
1182
|
+
const flush = () => {
|
|
1183
|
+
if (!notifyScheduledLow) return;
|
|
1184
|
+
flushNotify();
|
|
1185
|
+
};
|
|
1186
|
+
const raf = globalThis.requestAnimationFrame;
|
|
1187
|
+
if (raf) {
|
|
1188
|
+
lowRafId = raf(flush);
|
|
1189
|
+
} else {
|
|
1190
|
+
lowTimeoutId = setTimeout(flush, lowPriorityDelayMs);
|
|
1191
|
+
}
|
|
1192
|
+
lowMaxTimeoutId = setTimeout(flush, lowPriorityMaxDelayMs);
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
cancelLow();
|
|
1196
|
+
if (notifyScheduled) return;
|
|
1197
|
+
notifyScheduled = true;
|
|
1198
|
+
queueMicrotask(flushNotify);
|
|
1199
|
+
};
|
|
1200
|
+
let fiber;
|
|
1201
|
+
const ensureSubscription = () => {
|
|
1202
|
+
if (fiber) return;
|
|
1203
|
+
fiber = runtime.runFork(
|
|
1204
|
+
import_effect6.Stream.runForEach(
|
|
1205
|
+
moduleRuntime.changesWithMeta((state) => state),
|
|
1206
|
+
({ value: state, meta }) => import_effect6.Effect.sync(() => {
|
|
1207
|
+
currentState = state;
|
|
1208
|
+
scheduleNotify(meta.priority);
|
|
1209
|
+
})
|
|
1210
|
+
)
|
|
1211
|
+
);
|
|
1212
|
+
};
|
|
1213
|
+
const refreshSnapshotIfStale = () => {
|
|
1214
|
+
if (currentState === void 0) {
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
try {
|
|
1218
|
+
const latest = runtime.runSync(moduleRuntime.getState);
|
|
1219
|
+
if (currentState === void 0 || !Object.is(currentState, latest)) {
|
|
1220
|
+
currentState = latest;
|
|
1221
|
+
scheduleNotify("normal");
|
|
1222
|
+
}
|
|
1223
|
+
} catch {
|
|
1224
|
+
}
|
|
1225
|
+
};
|
|
1226
|
+
const getSnapshot = () => {
|
|
1227
|
+
if (currentState !== void 0) return currentState;
|
|
1228
|
+
currentState = runtime.runSync(moduleRuntime.getState);
|
|
1229
|
+
return currentState;
|
|
1230
|
+
};
|
|
1231
|
+
const subscribe = (listener) => {
|
|
1232
|
+
listeners.add(listener);
|
|
1233
|
+
ensureSubscription();
|
|
1234
|
+
refreshSnapshotIfStale();
|
|
1235
|
+
return () => {
|
|
1236
|
+
listeners.delete(listener);
|
|
1237
|
+
if (listeners.size > 0) return;
|
|
1238
|
+
const running = fiber;
|
|
1239
|
+
if (!running) return;
|
|
1240
|
+
fiber = void 0;
|
|
1241
|
+
cancelLow();
|
|
1242
|
+
runtime.runFork(import_effect6.Fiber.interrupt(running));
|
|
1243
|
+
};
|
|
1244
|
+
};
|
|
1245
|
+
const store = { getSnapshot, subscribe };
|
|
1246
|
+
byModule.set(moduleRuntime, store);
|
|
1247
|
+
return store;
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
// src/internal/store/ModuleRuntimeSelectorExternalStore.ts
|
|
1251
|
+
var import_effect7 = require("effect");
|
|
1252
|
+
|
|
1253
|
+
// src/internal/hooks/shallow.ts
|
|
1254
|
+
var hasObjectShape = (value) => typeof value === "object" && value !== null;
|
|
1255
|
+
var hasIterator = (value) => hasObjectShape(value) && typeof value[Symbol.iterator] === "function";
|
|
1256
|
+
var shallow = (previous, next) => {
|
|
1257
|
+
if (Object.is(previous, next)) return true;
|
|
1258
|
+
if (!hasObjectShape(previous) || !hasObjectShape(next)) {
|
|
1259
|
+
return false;
|
|
1260
|
+
}
|
|
1261
|
+
if (Array.isArray(previous) && Array.isArray(next)) {
|
|
1262
|
+
if (previous.length !== next.length) return false;
|
|
1263
|
+
for (let i = 0; i < previous.length; i++) {
|
|
1264
|
+
if (!Object.is(previous[i], next[i])) return false;
|
|
1265
|
+
}
|
|
1266
|
+
return true;
|
|
1267
|
+
}
|
|
1268
|
+
if (previous instanceof Map && next instanceof Map) {
|
|
1269
|
+
if (previous.size !== next.size) return false;
|
|
1270
|
+
for (const [key, value] of previous) {
|
|
1271
|
+
if (!next.has(key)) return false;
|
|
1272
|
+
if (!Object.is(value, next.get(key))) return false;
|
|
1273
|
+
}
|
|
1274
|
+
return true;
|
|
1275
|
+
}
|
|
1276
|
+
if (previous instanceof Set && next instanceof Set) {
|
|
1277
|
+
if (previous.size !== next.size) return false;
|
|
1278
|
+
for (const value of previous) {
|
|
1279
|
+
if (!next.has(value)) return false;
|
|
1280
|
+
}
|
|
1281
|
+
return true;
|
|
1282
|
+
}
|
|
1283
|
+
if (hasIterator(previous) && hasIterator(next)) {
|
|
1284
|
+
const a = previous[Symbol.iterator]();
|
|
1285
|
+
const b = next[Symbol.iterator]();
|
|
1286
|
+
while (true) {
|
|
1287
|
+
const ra = a.next();
|
|
1288
|
+
const rb = b.next();
|
|
1289
|
+
if (ra.done || rb.done) return ra.done === rb.done;
|
|
1290
|
+
if (!Object.is(ra.value, rb.value)) return false;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
const prevKeys = Object.keys(previous);
|
|
1294
|
+
const nextKeys = Object.keys(next);
|
|
1295
|
+
if (prevKeys.length !== nextKeys.length) return false;
|
|
1296
|
+
for (const key of prevKeys) {
|
|
1297
|
+
if (!Object.prototype.hasOwnProperty.call(next, key)) return false;
|
|
1298
|
+
if (!Object.is(previous[key], next[key])) return false;
|
|
1299
|
+
}
|
|
1300
|
+
return true;
|
|
1301
|
+
};
|
|
1302
|
+
|
|
1303
|
+
// src/internal/store/ModuleRuntimeSelectorExternalStore.ts
|
|
1304
|
+
var storesByRuntime2 = /* @__PURE__ */ new WeakMap();
|
|
1305
|
+
var getStoreMapForRuntime2 = (runtime) => {
|
|
1306
|
+
const cached = storesByRuntime2.get(runtime);
|
|
1307
|
+
if (cached) return cached;
|
|
1308
|
+
const next = /* @__PURE__ */ new WeakMap();
|
|
1309
|
+
storesByRuntime2.set(runtime, next);
|
|
1310
|
+
return next;
|
|
1311
|
+
};
|
|
1312
|
+
var getOrCreateSelectorMapForModule = (byModule, moduleRuntime) => {
|
|
1313
|
+
const cached = byModule.get(moduleRuntime);
|
|
1314
|
+
if (cached) return cached;
|
|
1315
|
+
const next = /* @__PURE__ */ new Map();
|
|
1316
|
+
byModule.set(moduleRuntime, next);
|
|
1317
|
+
return next;
|
|
1318
|
+
};
|
|
1319
|
+
var equalsValue = (readQuery, a, b) => {
|
|
1320
|
+
if (readQuery.equalsKind === "custom" && typeof readQuery.equals === "function") {
|
|
1321
|
+
return readQuery.equals(a, b);
|
|
1322
|
+
}
|
|
1323
|
+
if (readQuery.equalsKind === "shallowStruct") {
|
|
1324
|
+
return shallow(a, b);
|
|
1325
|
+
}
|
|
1326
|
+
return Object.is(a, b);
|
|
1327
|
+
};
|
|
1328
|
+
var getModuleRuntimeSelectorExternalStore = (runtime, moduleRuntime, selectorReadQuery, options) => {
|
|
1329
|
+
const byModule = getStoreMapForRuntime2(runtime);
|
|
1330
|
+
const bySelector = getOrCreateSelectorMapForModule(byModule, moduleRuntime);
|
|
1331
|
+
const cached = bySelector.get(selectorReadQuery.selectorId);
|
|
1332
|
+
if (cached) {
|
|
1333
|
+
return cached;
|
|
1334
|
+
}
|
|
1335
|
+
let currentValue;
|
|
1336
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1337
|
+
const lowPriorityDelayMs = options?.lowPriorityDelayMs ?? 16;
|
|
1338
|
+
const lowPriorityMaxDelayMs = options?.lowPriorityMaxDelayMs ?? 50;
|
|
1339
|
+
let notifyScheduled = false;
|
|
1340
|
+
let notifyScheduledLow = false;
|
|
1341
|
+
let lowTimeoutId;
|
|
1342
|
+
let lowMaxTimeoutId;
|
|
1343
|
+
let lowRafId;
|
|
1344
|
+
const cancelLow = () => {
|
|
1345
|
+
if (!notifyScheduledLow) return;
|
|
1346
|
+
notifyScheduledLow = false;
|
|
1347
|
+
if (lowTimeoutId != null) {
|
|
1348
|
+
clearTimeout(lowTimeoutId);
|
|
1349
|
+
lowTimeoutId = void 0;
|
|
1350
|
+
}
|
|
1351
|
+
if (lowMaxTimeoutId != null) {
|
|
1352
|
+
clearTimeout(lowMaxTimeoutId);
|
|
1353
|
+
lowMaxTimeoutId = void 0;
|
|
1354
|
+
}
|
|
1355
|
+
const cancel = globalThis.cancelAnimationFrame;
|
|
1356
|
+
if (cancel && typeof lowRafId === "number") {
|
|
1357
|
+
cancel(lowRafId);
|
|
1358
|
+
lowRafId = void 0;
|
|
1359
|
+
}
|
|
1360
|
+
};
|
|
1361
|
+
const flushNotify = () => {
|
|
1362
|
+
notifyScheduled = false;
|
|
1363
|
+
cancelLow();
|
|
1364
|
+
for (const listener of listeners) {
|
|
1365
|
+
listener();
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1368
|
+
const scheduleNotify = (priority) => {
|
|
1369
|
+
if (priority === "low") {
|
|
1370
|
+
if (notifyScheduled) return;
|
|
1371
|
+
if (notifyScheduledLow) return;
|
|
1372
|
+
notifyScheduledLow = true;
|
|
1373
|
+
const flush = () => {
|
|
1374
|
+
if (!notifyScheduledLow) return;
|
|
1375
|
+
flushNotify();
|
|
1376
|
+
};
|
|
1377
|
+
const raf = globalThis.requestAnimationFrame;
|
|
1378
|
+
if (raf) {
|
|
1379
|
+
lowRafId = raf(flush);
|
|
1380
|
+
} else {
|
|
1381
|
+
lowTimeoutId = setTimeout(flush, lowPriorityDelayMs);
|
|
1382
|
+
}
|
|
1383
|
+
lowMaxTimeoutId = setTimeout(flush, lowPriorityMaxDelayMs);
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
cancelLow();
|
|
1387
|
+
if (notifyScheduled) return;
|
|
1388
|
+
notifyScheduled = true;
|
|
1389
|
+
queueMicrotask(flushNotify);
|
|
1390
|
+
};
|
|
1391
|
+
let fiber;
|
|
1392
|
+
const ensureSubscription = () => {
|
|
1393
|
+
if (fiber) return;
|
|
1394
|
+
fiber = runtime.runFork(
|
|
1395
|
+
import_effect7.Stream.runForEach(
|
|
1396
|
+
moduleRuntime.changesReadQueryWithMeta(selectorReadQuery),
|
|
1397
|
+
({ value, meta }) => import_effect7.Effect.sync(() => {
|
|
1398
|
+
currentValue = value;
|
|
1399
|
+
scheduleNotify(meta.priority);
|
|
1400
|
+
})
|
|
1401
|
+
)
|
|
1402
|
+
);
|
|
1403
|
+
};
|
|
1404
|
+
const refreshSnapshotIfStale = () => {
|
|
1405
|
+
if (currentValue === void 0) {
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
try {
|
|
1409
|
+
const state = runtime.runSync(moduleRuntime.getState);
|
|
1410
|
+
const next = selectorReadQuery.select(state);
|
|
1411
|
+
if (currentValue === void 0 || !equalsValue(selectorReadQuery, currentValue, next)) {
|
|
1412
|
+
currentValue = next;
|
|
1413
|
+
scheduleNotify("normal");
|
|
1414
|
+
}
|
|
1415
|
+
} catch {
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1418
|
+
const getSnapshot = () => {
|
|
1419
|
+
if (currentValue !== void 0) return currentValue;
|
|
1420
|
+
const state = runtime.runSync(moduleRuntime.getState);
|
|
1421
|
+
currentValue = selectorReadQuery.select(state);
|
|
1422
|
+
return currentValue;
|
|
1423
|
+
};
|
|
1424
|
+
const subscribe = (listener) => {
|
|
1425
|
+
listeners.add(listener);
|
|
1426
|
+
ensureSubscription();
|
|
1427
|
+
refreshSnapshotIfStale();
|
|
1428
|
+
return () => {
|
|
1429
|
+
listeners.delete(listener);
|
|
1430
|
+
if (listeners.size > 0) return;
|
|
1431
|
+
const running = fiber;
|
|
1432
|
+
if (!running) return;
|
|
1433
|
+
fiber = void 0;
|
|
1434
|
+
cancelLow();
|
|
1435
|
+
runtime.runFork(import_effect7.Fiber.interrupt(running));
|
|
1436
|
+
};
|
|
1437
|
+
};
|
|
1438
|
+
const store = { getSnapshot, subscribe };
|
|
1439
|
+
bySelector.set(selectorReadQuery.selectorId, store);
|
|
1440
|
+
return store;
|
|
1441
|
+
};
|
|
1442
|
+
|
|
1443
|
+
// src/internal/hooks/useSelector.ts
|
|
1444
|
+
function useSelector(handle, selector, equalityFn) {
|
|
1445
|
+
const runtimeContext = (0, import_react5.useContext)(RuntimeContext);
|
|
1446
|
+
if (!runtimeContext) {
|
|
1447
|
+
throw new RuntimeProviderNotFoundError("useSelector");
|
|
1448
|
+
}
|
|
1449
|
+
const runtime = runtimeContext.runtime;
|
|
1450
|
+
const moduleRuntime = useModuleRuntime(handle);
|
|
1451
|
+
const actualSelector = selector ?? ((state) => state);
|
|
1452
|
+
const selectorReadQuery = (0, import_react5.useMemo)(
|
|
1453
|
+
() => typeof selector === "function" ? Logix5.ReadQuery.compile(selector) : void 0,
|
|
1454
|
+
[selector]
|
|
1455
|
+
);
|
|
1456
|
+
const actualEqualityFn = (0, import_react5.useMemo)(() => {
|
|
1457
|
+
if (typeof equalityFn === "function") return equalityFn;
|
|
1458
|
+
if (typeof selector !== "function") return Object.is;
|
|
1459
|
+
return selectorReadQuery?.equalsKind === "shallowStruct" ? shallow : Object.is;
|
|
1460
|
+
}, [equalityFn, selector, selectorReadQuery?.equalsKind]);
|
|
1461
|
+
const useStaticLane = typeof selector === "function" && selectorReadQuery?.lane === "static";
|
|
1462
|
+
const store = (0, import_react5.useMemo)(
|
|
1463
|
+
() => useStaticLane && selectorReadQuery ? getModuleRuntimeSelectorExternalStore(
|
|
1464
|
+
runtime,
|
|
1465
|
+
moduleRuntime,
|
|
1466
|
+
selectorReadQuery,
|
|
1467
|
+
{
|
|
1468
|
+
lowPriorityDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
|
|
1469
|
+
lowPriorityMaxDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs
|
|
1470
|
+
}
|
|
1471
|
+
) : getModuleRuntimeExternalStore(
|
|
1472
|
+
runtime,
|
|
1473
|
+
moduleRuntime,
|
|
1474
|
+
{
|
|
1475
|
+
lowPriorityDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
|
|
1476
|
+
lowPriorityMaxDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs
|
|
1477
|
+
}
|
|
1478
|
+
),
|
|
1479
|
+
[
|
|
1480
|
+
moduleRuntime,
|
|
1481
|
+
runtime,
|
|
1482
|
+
runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
|
|
1483
|
+
runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs,
|
|
1484
|
+
selectorReadQuery,
|
|
1485
|
+
useStaticLane
|
|
1486
|
+
]
|
|
1487
|
+
);
|
|
1488
|
+
const selected = (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
1489
|
+
store.subscribe,
|
|
1490
|
+
store.getSnapshot,
|
|
1491
|
+
store.getSnapshot,
|
|
1492
|
+
useStaticLane ? (snapshot) => snapshot : (snapshot) => actualSelector(snapshot),
|
|
1493
|
+
actualEqualityFn
|
|
1494
|
+
);
|
|
1495
|
+
(0, import_react5.useEffect)(() => {
|
|
1496
|
+
if (!(0, import_Env.isDevEnv)() && !Logix5.Debug.isDevtoolsEnabled()) {
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
const instanceId = moduleRuntime.instanceId;
|
|
1500
|
+
let fieldPaths;
|
|
1501
|
+
let selectorKey;
|
|
1502
|
+
if (typeof selector === "function") {
|
|
1503
|
+
const meta = selector;
|
|
1504
|
+
const rawFieldPaths = meta.fieldPaths;
|
|
1505
|
+
if (Array.isArray(rawFieldPaths)) {
|
|
1506
|
+
const paths = rawFieldPaths.filter((p) => typeof p === "string");
|
|
1507
|
+
fieldPaths = paths.length > 0 ? paths.slice() : void 0;
|
|
1508
|
+
}
|
|
1509
|
+
const rawDebugKey = meta.debugKey;
|
|
1510
|
+
selectorKey = typeof rawDebugKey === "string" && rawDebugKey.length > 0 ? rawDebugKey : typeof selector.name === "string" && selector.name.length > 0 ? selector.name : void 0;
|
|
1511
|
+
}
|
|
1512
|
+
const effect = Logix5.Debug.record({
|
|
1513
|
+
type: "trace:react-selector",
|
|
1514
|
+
moduleId: moduleRuntime.moduleId,
|
|
1515
|
+
instanceId,
|
|
1516
|
+
data: {
|
|
1517
|
+
componentLabel: "useSelector",
|
|
1518
|
+
selectorKey,
|
|
1519
|
+
fieldPaths,
|
|
1520
|
+
selectorId: selectorReadQuery?.selectorId,
|
|
1521
|
+
lane: selectorReadQuery?.lane,
|
|
1522
|
+
producer: selectorReadQuery?.producer,
|
|
1523
|
+
fallbackReason: selectorReadQuery?.fallbackReason,
|
|
1524
|
+
readsDigest: selectorReadQuery?.readsDigest,
|
|
1525
|
+
equalsKind: selectorReadQuery?.equalsKind,
|
|
1526
|
+
strictModePhase: "commit"
|
|
1527
|
+
}
|
|
1528
|
+
});
|
|
1529
|
+
runtime.runFork(effect);
|
|
1530
|
+
}, [runtime, moduleRuntime, selector, selected, selectorReadQuery]);
|
|
1531
|
+
return selected;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// src/internal/store/resolveImportedModuleRef.ts
|
|
1535
|
+
var Logix6 = __toESM(require("@logixjs/core"), 1);
|
|
1536
|
+
var getOrCreateWeakMap = (map, key, make) => {
|
|
1537
|
+
const cached = map.get(key);
|
|
1538
|
+
if (cached) return cached;
|
|
1539
|
+
const next = make();
|
|
1540
|
+
map.set(key, next);
|
|
1541
|
+
return next;
|
|
1542
|
+
};
|
|
1543
|
+
var cacheByRuntime = /* @__PURE__ */ new WeakMap();
|
|
1544
|
+
var resolveImportedModuleRef = (runtime, parentRuntime, module2) => {
|
|
1545
|
+
const byParent = getOrCreateWeakMap(
|
|
1546
|
+
cacheByRuntime,
|
|
1547
|
+
runtime,
|
|
1548
|
+
() => /* @__PURE__ */ new WeakMap()
|
|
1549
|
+
);
|
|
1550
|
+
const byModule = getOrCreateWeakMap(
|
|
1551
|
+
byParent,
|
|
1552
|
+
parentRuntime,
|
|
1553
|
+
() => /* @__PURE__ */ new WeakMap()
|
|
1554
|
+
);
|
|
1555
|
+
const cached = byModule.get(module2);
|
|
1556
|
+
if (cached) {
|
|
1557
|
+
return cached;
|
|
1558
|
+
}
|
|
1559
|
+
const importsScope = Logix6.InternalContracts.getImportsScope(parentRuntime);
|
|
1560
|
+
const childRuntime = importsScope.get(module2);
|
|
1561
|
+
if (childRuntime) {
|
|
1562
|
+
const dispatch = Object.assign(
|
|
1563
|
+
(action) => {
|
|
1564
|
+
runtime.runFork(childRuntime.dispatch(action));
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
batch: (actions2) => {
|
|
1568
|
+
runtime.runFork(
|
|
1569
|
+
childRuntime.dispatchBatch(
|
|
1570
|
+
actions2
|
|
1571
|
+
)
|
|
1572
|
+
);
|
|
1573
|
+
},
|
|
1574
|
+
lowPriority: (action) => {
|
|
1575
|
+
runtime.runFork(
|
|
1576
|
+
childRuntime.dispatchLowPriority(action)
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
);
|
|
1581
|
+
const actions = makeModuleActions(dispatch);
|
|
1582
|
+
const dispatchers = makeModuleDispatchers(dispatch, module2.actions);
|
|
1583
|
+
const ref = {
|
|
1584
|
+
def: module2,
|
|
1585
|
+
runtime: childRuntime,
|
|
1586
|
+
dispatch,
|
|
1587
|
+
actions,
|
|
1588
|
+
dispatchers,
|
|
1589
|
+
imports: {
|
|
1590
|
+
get: (m) => resolveImportedModuleRef(runtime, childRuntime, m)
|
|
1591
|
+
},
|
|
1592
|
+
getState: childRuntime.getState,
|
|
1593
|
+
setState: childRuntime.setState,
|
|
1594
|
+
actions$: childRuntime.actions$,
|
|
1595
|
+
changes: childRuntime.changes,
|
|
1596
|
+
ref: childRuntime.ref
|
|
1597
|
+
};
|
|
1598
|
+
byModule.set(module2, ref);
|
|
1599
|
+
return ref;
|
|
1600
|
+
}
|
|
1601
|
+
const parentId = parentRuntime.moduleId;
|
|
1602
|
+
const tokenId = String(module2.id);
|
|
1603
|
+
const parentInstanceId = parentRuntime.instanceId;
|
|
1604
|
+
const fix = (0, import_Env.isDevEnv)() ? [
|
|
1605
|
+
"- Ensure the child is imported in the same scope.",
|
|
1606
|
+
` Example: ${parentId}.implement({ imports: [${tokenId}.impl], ... })`,
|
|
1607
|
+
"- Ensure parentRuntime is an instance scope (not a ModuleTag singleton).",
|
|
1608
|
+
" Example: useModule(ParentImpl, { key }) / useModule(ParentImpl) / useLocalModule(ParentModule, ...)",
|
|
1609
|
+
"- If you intentionally want a singleton (not an imported child), use useModule(Child.tag) (ModuleTag) in the current React runtime environment.",
|
|
1610
|
+
"- If you intentionally want the root provider singleton (ignore RuntimeProvider.layer overrides), use runtime.runSync(Root.resolve(Child.tag))."
|
|
1611
|
+
] : [];
|
|
1612
|
+
const err = new Error(
|
|
1613
|
+
(0, import_Env.isDevEnv)() ? [
|
|
1614
|
+
"[MissingImportedModuleError] Cannot resolve imported module from parent imports scope.",
|
|
1615
|
+
"",
|
|
1616
|
+
`tokenId: ${tokenId}`,
|
|
1617
|
+
"entrypoint: react.useImportedModule/imports.get",
|
|
1618
|
+
"mode: strict",
|
|
1619
|
+
`startScope: moduleId=${parentId}, instanceId=${parentInstanceId}`,
|
|
1620
|
+
"",
|
|
1621
|
+
"fix:",
|
|
1622
|
+
...fix
|
|
1623
|
+
].join("\n") : "[MissingImportedModuleError] imported module runtime not found"
|
|
1624
|
+
);
|
|
1625
|
+
err.tokenId = tokenId;
|
|
1626
|
+
err.entrypoint = "react.useImportedModule/imports.get";
|
|
1627
|
+
err.mode = "strict";
|
|
1628
|
+
err.startScope = {
|
|
1629
|
+
moduleId: parentId,
|
|
1630
|
+
instanceId: parentInstanceId
|
|
1631
|
+
};
|
|
1632
|
+
err.fix = fix;
|
|
1633
|
+
err.name = "MissingImportedModuleError";
|
|
1634
|
+
throw err;
|
|
1635
|
+
};
|
|
1636
|
+
|
|
1637
|
+
// src/internal/hooks/useStableId.ts
|
|
1638
|
+
var import_react6 = __toESM(require("react"), 1);
|
|
1639
|
+
var useStableId = () => {
|
|
1640
|
+
return import_react6.default.useId();
|
|
1641
|
+
};
|
|
1642
|
+
|
|
1643
|
+
// src/internal/hooks/useModule.ts
|
|
1644
|
+
var isModuleImpl = (handle) => Boolean(handle) && typeof handle === "object" && handle._tag === "ModuleImpl";
|
|
1645
|
+
var isModule = (handle) => Logix7.Module.hasImpl(handle);
|
|
1646
|
+
var isModuleDef = (handle) => Logix7.Module.is(handle) && handle._kind === "ModuleDef";
|
|
1647
|
+
function useModule(handle, selectorOrOptions, equalityFn) {
|
|
1648
|
+
const runtimeBase = useRuntime();
|
|
1649
|
+
const runtimeContext = import_react7.default.useContext(RuntimeContext);
|
|
1650
|
+
if (!runtimeContext) {
|
|
1651
|
+
throw new RuntimeProviderNotFoundError("useModule");
|
|
1652
|
+
}
|
|
1653
|
+
const normalizedHandle = isModule(handle) ? handle.impl : isModuleDef(handle) ? handle.tag : handle;
|
|
1654
|
+
let selector;
|
|
1655
|
+
let options;
|
|
1656
|
+
if (isModuleImpl(normalizedHandle)) {
|
|
1657
|
+
if (typeof selectorOrOptions === "function") {
|
|
1658
|
+
selector = selectorOrOptions;
|
|
1659
|
+
} else if (selectorOrOptions && typeof selectorOrOptions === "object") {
|
|
1660
|
+
options = selectorOrOptions;
|
|
1661
|
+
}
|
|
1662
|
+
} else {
|
|
1663
|
+
if (typeof selectorOrOptions === "function" || selectorOrOptions === void 0) {
|
|
1664
|
+
selector = selectorOrOptions;
|
|
1665
|
+
} else if (selectorOrOptions && typeof selectorOrOptions === "object") {
|
|
1666
|
+
throw new Error("useModule(handle, options) \u4EC5\u652F\u6301 ModuleImpl \u53E5\u67C4");
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
let runtime;
|
|
1670
|
+
if (isModuleImpl(normalizedHandle)) {
|
|
1671
|
+
const cache = import_react7.default.useMemo(
|
|
1672
|
+
() => getModuleCache(runtimeBase, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion),
|
|
1673
|
+
[runtimeBase, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion]
|
|
1674
|
+
);
|
|
1675
|
+
const deps = options?.deps ?? [];
|
|
1676
|
+
const depsHash = stableHash(deps);
|
|
1677
|
+
const explicitSuspend = options?.suspend === true;
|
|
1678
|
+
const suspend = explicitSuspend || options?.suspend !== false && runtimeContext.policy.moduleImplMode === "suspend";
|
|
1679
|
+
const gcTime = options?.gcTime ?? runtimeContext.reactConfigSnapshot.gcTime;
|
|
1680
|
+
let initTimeoutMs = suspend ? options?.initTimeoutMs : void 0;
|
|
1681
|
+
if (suspend && initTimeoutMs === void 0) {
|
|
1682
|
+
initTimeoutMs = runtimeContext.reactConfigSnapshot.initTimeoutMs;
|
|
1683
|
+
}
|
|
1684
|
+
if (explicitSuspend && (!options || !options.key)) {
|
|
1685
|
+
if ((0, import_Env.isDevEnv)()) {
|
|
1686
|
+
throw new Error(
|
|
1687
|
+
"[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"
|
|
1688
|
+
);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
const componentId = useStableId();
|
|
1692
|
+
const moduleId = normalizedHandle.module.id ?? "ModuleImpl";
|
|
1693
|
+
const preloadKey = runtimeContext.policy.preload?.keysByModuleId.get(moduleId);
|
|
1694
|
+
const baseKey = preloadKey ?? options?.key ?? (suspend ? `impl:${moduleId}` : `impl:${moduleId}:${componentId}`);
|
|
1695
|
+
const key = depsHash ? `${baseKey}:${depsHash}` : baseKey;
|
|
1696
|
+
const ownerId = moduleId;
|
|
1697
|
+
const baseFactory = import_react7.default.useMemo(
|
|
1698
|
+
() => (scope) => import_effect8.Layer.buildWithScope(normalizedHandle.layer, scope).pipe(
|
|
1699
|
+
import_effect8.Effect.map(
|
|
1700
|
+
(context) => import_effect8.Context.get(context, normalizedHandle.module)
|
|
1701
|
+
)
|
|
1702
|
+
),
|
|
1703
|
+
[normalizedHandle]
|
|
1704
|
+
);
|
|
1705
|
+
const factory = import_react7.default.useMemo(() => {
|
|
1706
|
+
if (!suspend || initTimeoutMs === void 0) {
|
|
1707
|
+
return baseFactory;
|
|
1708
|
+
}
|
|
1709
|
+
return (scope) => baseFactory(scope).pipe(
|
|
1710
|
+
import_effect8.Effect.timeoutFail({
|
|
1711
|
+
duration: initTimeoutMs,
|
|
1712
|
+
onTimeout: () => new Error(`[useModule] Module "${ownerId}" initialization timed out after ${initTimeoutMs}ms`)
|
|
1713
|
+
})
|
|
1714
|
+
);
|
|
1715
|
+
}, [baseFactory, suspend, initTimeoutMs, ownerId]);
|
|
1716
|
+
const moduleRuntime = suspend ? cache.read(key, factory, gcTime, ownerId, {
|
|
1717
|
+
entrypoint: "react.useModule",
|
|
1718
|
+
policyMode: runtimeContext.policy.mode,
|
|
1719
|
+
yield: runtimeContext.policy.yield
|
|
1720
|
+
}) : cache.readSync(key, factory, gcTime, ownerId, {
|
|
1721
|
+
entrypoint: "react.useModule",
|
|
1722
|
+
policyMode: runtimeContext.policy.mode,
|
|
1723
|
+
warnSyncBlockingThresholdMs: 5
|
|
1724
|
+
});
|
|
1725
|
+
import_react7.default.useEffect(() => cache.retain(key), [cache, key]);
|
|
1726
|
+
runtime = moduleRuntime;
|
|
1727
|
+
} else {
|
|
1728
|
+
runtime = useModuleRuntime(normalizedHandle);
|
|
1729
|
+
}
|
|
1730
|
+
import_react7.default.useEffect(() => {
|
|
1731
|
+
if (!isModuleImpl(normalizedHandle)) {
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1734
|
+
const opt = options;
|
|
1735
|
+
const label = opt && "label" in opt && opt.label || opt && opt.key;
|
|
1736
|
+
if (!label) {
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
const effect = Logix7.Debug.record({
|
|
1740
|
+
type: "trace:instanceLabel",
|
|
1741
|
+
moduleId: normalizedHandle.module.id,
|
|
1742
|
+
instanceId: runtime.instanceId,
|
|
1743
|
+
data: { label }
|
|
1744
|
+
});
|
|
1745
|
+
runtimeBase.runFork(effect);
|
|
1746
|
+
}, [runtimeBase, runtime, normalizedHandle, options]);
|
|
1747
|
+
import_react7.default.useEffect(() => {
|
|
1748
|
+
if (!(0, import_Env.isDevEnv)() && !Logix7.Debug.isDevtoolsEnabled()) {
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
if (!runtime.instanceId) {
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
const effect = Logix7.Debug.record({
|
|
1755
|
+
type: "trace:react-render",
|
|
1756
|
+
moduleId: runtime.moduleId,
|
|
1757
|
+
instanceId: runtime.instanceId,
|
|
1758
|
+
data: {
|
|
1759
|
+
componentLabel: "useModule",
|
|
1760
|
+
strictModePhase: "commit"
|
|
1761
|
+
}
|
|
1762
|
+
});
|
|
1763
|
+
runtimeBase.runFork(effect);
|
|
1764
|
+
}, [runtimeBase, runtime]);
|
|
1765
|
+
if (selector) {
|
|
1766
|
+
if (isModuleImpl(normalizedHandle)) {
|
|
1767
|
+
return useSelector(runtime, selector, equalityFn);
|
|
1768
|
+
}
|
|
1769
|
+
return useSelector(normalizedHandle, selector, equalityFn);
|
|
1770
|
+
}
|
|
1771
|
+
const def = import_react7.default.useMemo(() => {
|
|
1772
|
+
if (isModule(handle) || isModuleDef(handle)) {
|
|
1773
|
+
return handle;
|
|
1774
|
+
}
|
|
1775
|
+
if (isModuleRef(handle)) {
|
|
1776
|
+
return handle.def;
|
|
1777
|
+
}
|
|
1778
|
+
if (isModuleImpl(handle)) {
|
|
1779
|
+
return handle.module;
|
|
1780
|
+
}
|
|
1781
|
+
if (handle && (typeof handle === "object" || typeof handle === "function") && handle._kind === "ModuleTag") {
|
|
1782
|
+
return handle;
|
|
1783
|
+
}
|
|
1784
|
+
if (isModuleImpl(normalizedHandle)) {
|
|
1785
|
+
return normalizedHandle.module;
|
|
1786
|
+
}
|
|
1787
|
+
if (isModuleRef(normalizedHandle)) {
|
|
1788
|
+
return normalizedHandle.def;
|
|
1789
|
+
}
|
|
1790
|
+
if (normalizedHandle && (typeof normalizedHandle === "object" || typeof normalizedHandle === "function") && normalizedHandle._kind === "ModuleTag") {
|
|
1791
|
+
return normalizedHandle;
|
|
1792
|
+
}
|
|
1793
|
+
return void 0;
|
|
1794
|
+
}, [handle, normalizedHandle]);
|
|
1795
|
+
const tokens = import_react7.default.useMemo(() => {
|
|
1796
|
+
if (!def || typeof def !== "object" && typeof def !== "function") {
|
|
1797
|
+
return void 0;
|
|
1798
|
+
}
|
|
1799
|
+
const candidate = def;
|
|
1800
|
+
if (!candidate.actions || typeof candidate.actions !== "object") {
|
|
1801
|
+
return void 0;
|
|
1802
|
+
}
|
|
1803
|
+
return candidate.actions;
|
|
1804
|
+
}, [def]);
|
|
1805
|
+
const dispatch = import_react7.default.useMemo(() => {
|
|
1806
|
+
const base = (action) => {
|
|
1807
|
+
runtimeBase.runFork(runtime.dispatch(action));
|
|
1808
|
+
};
|
|
1809
|
+
return Object.assign(base, {
|
|
1810
|
+
batch: (actions2) => {
|
|
1811
|
+
runtimeBase.runFork(runtime.dispatchBatch(actions2));
|
|
1812
|
+
},
|
|
1813
|
+
lowPriority: (action) => {
|
|
1814
|
+
runtimeBase.runFork(runtime.dispatchLowPriority(action));
|
|
1815
|
+
}
|
|
1816
|
+
});
|
|
1817
|
+
}, [runtimeBase, runtime]);
|
|
1818
|
+
const extendTag = import_react7.default.useMemo(() => {
|
|
1819
|
+
if (isModuleImpl(normalizedHandle)) {
|
|
1820
|
+
return normalizedHandle.module;
|
|
1821
|
+
}
|
|
1822
|
+
return normalizedHandle;
|
|
1823
|
+
}, [normalizedHandle]);
|
|
1824
|
+
const actions = import_react7.default.useMemo(() => makeModuleActions(dispatch), [dispatch]);
|
|
1825
|
+
const dispatchers = import_react7.default.useMemo(
|
|
1826
|
+
() => tokens ? makeModuleDispatchers(dispatch, tokens) : makeModuleDispatchers(dispatch),
|
|
1827
|
+
[dispatch, tokens]
|
|
1828
|
+
);
|
|
1829
|
+
return import_react7.default.useMemo(() => {
|
|
1830
|
+
const base = {
|
|
1831
|
+
def,
|
|
1832
|
+
runtime,
|
|
1833
|
+
dispatch,
|
|
1834
|
+
actions,
|
|
1835
|
+
dispatchers,
|
|
1836
|
+
imports: {
|
|
1837
|
+
get: (module2) => resolveImportedModuleRef(runtimeBase, runtime, module2)
|
|
1838
|
+
},
|
|
1839
|
+
getState: runtime.getState,
|
|
1840
|
+
setState: runtime.setState,
|
|
1841
|
+
actions$: runtime.actions$,
|
|
1842
|
+
changes: runtime.changes,
|
|
1843
|
+
ref: runtime.ref
|
|
1844
|
+
};
|
|
1845
|
+
return applyHandleExtend(extendTag, runtime, base);
|
|
1846
|
+
}, [runtimeBase, runtime, dispatch, actions, dispatchers, extendTag, def]);
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
// src/internal/provider/RuntimeProvider.tsx
|
|
1850
|
+
var import_react9 = __toESM(require("react"), 1);
|
|
1851
|
+
var import_effect10 = require("effect");
|
|
1852
|
+
var Logix9 = __toESM(require("@logixjs/core"), 1);
|
|
1853
|
+
|
|
1854
|
+
// src/internal/provider/config.ts
|
|
1855
|
+
var import_effect9 = require("effect");
|
|
1856
|
+
var ReactRuntimeConfigTag = class extends import_effect9.Context.Tag("@logixjs/react/RuntimeConfig")() {
|
|
1857
|
+
};
|
|
1858
|
+
var DEFAULT_CONFIG = {
|
|
1859
|
+
gcTime: 500,
|
|
1860
|
+
initTimeoutMs: void 0,
|
|
1861
|
+
lowPriorityDelayMs: 16,
|
|
1862
|
+
lowPriorityMaxDelayMs: 50
|
|
1863
|
+
};
|
|
1864
|
+
var DEFAULT_CONFIG_SNAPSHOT = {
|
|
1865
|
+
gcTime: DEFAULT_CONFIG.gcTime,
|
|
1866
|
+
initTimeoutMs: DEFAULT_CONFIG.initTimeoutMs,
|
|
1867
|
+
lowPriorityDelayMs: DEFAULT_CONFIG.lowPriorityDelayMs ?? 16,
|
|
1868
|
+
lowPriorityMaxDelayMs: DEFAULT_CONFIG.lowPriorityMaxDelayMs ?? 50,
|
|
1869
|
+
source: "default"
|
|
1870
|
+
};
|
|
1871
|
+
var ReactModuleConfigFromEnv = {
|
|
1872
|
+
/**
|
|
1873
|
+
* Default gcTime (ms) used as the idle keep-alive time for ModuleCache.
|
|
1874
|
+
* - Applies when not explicitly specified in useModule(options.gcTime).
|
|
1875
|
+
* - Default: 500ms (StrictMode jitter protection).
|
|
1876
|
+
*/
|
|
1877
|
+
gcTime: import_effect9.Config.number("logix.react.gc_time").pipe(import_effect9.Config.withDefault(DEFAULT_CONFIG.gcTime)),
|
|
1878
|
+
/**
|
|
1879
|
+
* Default init timeout (ms), only effective when suspend:true.
|
|
1880
|
+
* - Uses Option<number> to represent "optional config": missing means init timeout is disabled.
|
|
1881
|
+
* - Callers can map Option.none to undefined.
|
|
1882
|
+
*/
|
|
1883
|
+
initTimeoutMs: import_effect9.Config.option(import_effect9.Config.number("logix.react.init_timeout_ms")),
|
|
1884
|
+
/**
|
|
1885
|
+
* Delay (ms) for low-priority notification scheduling.
|
|
1886
|
+
* - Roughly "defer to the next frame" cadence (default 16ms).
|
|
1887
|
+
*/
|
|
1888
|
+
lowPriorityDelayMs: import_effect9.Config.number("logix.react.low_priority_delay_ms").pipe(
|
|
1889
|
+
import_effect9.Config.withDefault(DEFAULT_CONFIG.lowPriorityDelayMs ?? 16)
|
|
1890
|
+
),
|
|
1891
|
+
/**
|
|
1892
|
+
* Maximum delay upper bound (ms) for low-priority notification scheduling.
|
|
1893
|
+
* - Ensures eventual delivery, avoiding indefinite coalescing under extreme high-frequency scenarios.
|
|
1894
|
+
* - Default 50ms.
|
|
1895
|
+
*/
|
|
1896
|
+
lowPriorityMaxDelayMs: import_effect9.Config.number("logix.react.low_priority_max_delay_ms").pipe(
|
|
1897
|
+
import_effect9.Config.withDefault(DEFAULT_CONFIG.lowPriorityMaxDelayMs ?? 50)
|
|
1898
|
+
)
|
|
1899
|
+
};
|
|
1900
|
+
var ReactModuleConfig = {
|
|
1901
|
+
gcTime: import_effect9.Effect.gen(function* () {
|
|
1902
|
+
const override = yield* import_effect9.Effect.serviceOption(ReactRuntimeConfigTag);
|
|
1903
|
+
if (import_effect9.Option.isSome(override)) {
|
|
1904
|
+
return override.value.gcTime;
|
|
1905
|
+
}
|
|
1906
|
+
const value = yield* ReactModuleConfigFromEnv.gcTime;
|
|
1907
|
+
return value;
|
|
1908
|
+
}),
|
|
1909
|
+
initTimeoutMs: import_effect9.Effect.gen(function* () {
|
|
1910
|
+
const override = yield* import_effect9.Effect.serviceOption(ReactRuntimeConfigTag);
|
|
1911
|
+
if (import_effect9.Option.isSome(override)) {
|
|
1912
|
+
const v = override.value.initTimeoutMs;
|
|
1913
|
+
return v === void 0 ? import_effect9.Option.none() : import_effect9.Option.some(v);
|
|
1914
|
+
}
|
|
1915
|
+
const opt = yield* ReactModuleConfigFromEnv.initTimeoutMs;
|
|
1916
|
+
return opt;
|
|
1917
|
+
}),
|
|
1918
|
+
lowPriorityDelayMs: import_effect9.Effect.gen(function* () {
|
|
1919
|
+
const override = yield* import_effect9.Effect.serviceOption(ReactRuntimeConfigTag);
|
|
1920
|
+
if (import_effect9.Option.isSome(override)) {
|
|
1921
|
+
return override.value.lowPriorityDelayMs ?? DEFAULT_CONFIG.lowPriorityDelayMs ?? 16;
|
|
1922
|
+
}
|
|
1923
|
+
const value = yield* ReactModuleConfigFromEnv.lowPriorityDelayMs;
|
|
1924
|
+
return value;
|
|
1925
|
+
}),
|
|
1926
|
+
lowPriorityMaxDelayMs: import_effect9.Effect.gen(function* () {
|
|
1927
|
+
const override = yield* import_effect9.Effect.serviceOption(ReactRuntimeConfigTag);
|
|
1928
|
+
if (import_effect9.Option.isSome(override)) {
|
|
1929
|
+
return override.value.lowPriorityMaxDelayMs ?? DEFAULT_CONFIG.lowPriorityMaxDelayMs ?? 50;
|
|
1930
|
+
}
|
|
1931
|
+
const value = yield* ReactModuleConfigFromEnv.lowPriorityMaxDelayMs;
|
|
1932
|
+
return value;
|
|
1933
|
+
})
|
|
1934
|
+
};
|
|
1935
|
+
var ReactRuntimeConfigSnapshot = {
|
|
1936
|
+
load: import_effect9.Effect.gen(function* () {
|
|
1937
|
+
const runtimeOverride = yield* import_effect9.Effect.serviceOption(ReactRuntimeConfigTag);
|
|
1938
|
+
if (import_effect9.Option.isSome(runtimeOverride)) {
|
|
1939
|
+
return {
|
|
1940
|
+
gcTime: runtimeOverride.value.gcTime,
|
|
1941
|
+
initTimeoutMs: runtimeOverride.value.initTimeoutMs,
|
|
1942
|
+
lowPriorityDelayMs: runtimeOverride.value.lowPriorityDelayMs ?? DEFAULT_CONFIG.lowPriorityDelayMs ?? 16,
|
|
1943
|
+
lowPriorityMaxDelayMs: runtimeOverride.value.lowPriorityMaxDelayMs ?? DEFAULT_CONFIG.lowPriorityMaxDelayMs ?? 50,
|
|
1944
|
+
source: "runtime"
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1947
|
+
const envGcTime = yield* ReactModuleConfigFromEnv.gcTime;
|
|
1948
|
+
const envInitTimeoutOpt = yield* ReactModuleConfigFromEnv.initTimeoutMs;
|
|
1949
|
+
const envInitTimeout = import_effect9.Option.getOrUndefined(envInitTimeoutOpt);
|
|
1950
|
+
const envLowPriorityDelayMs = yield* ReactModuleConfigFromEnv.lowPriorityDelayMs;
|
|
1951
|
+
const envLowPriorityMaxDelayMs = yield* ReactModuleConfigFromEnv.lowPriorityMaxDelayMs;
|
|
1952
|
+
const fromConfig = envGcTime !== DEFAULT_CONFIG.gcTime || import_effect9.Option.isSome(envInitTimeoutOpt) || envLowPriorityDelayMs !== (DEFAULT_CONFIG.lowPriorityDelayMs ?? 16) || envLowPriorityMaxDelayMs !== (DEFAULT_CONFIG.lowPriorityMaxDelayMs ?? 50);
|
|
1953
|
+
if (fromConfig) {
|
|
1954
|
+
return {
|
|
1955
|
+
gcTime: envGcTime,
|
|
1956
|
+
initTimeoutMs: envInitTimeout,
|
|
1957
|
+
lowPriorityDelayMs: envLowPriorityDelayMs,
|
|
1958
|
+
lowPriorityMaxDelayMs: envLowPriorityMaxDelayMs,
|
|
1959
|
+
source: "config"
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
return DEFAULT_CONFIG_SNAPSHOT;
|
|
1963
|
+
})
|
|
1964
|
+
};
|
|
1965
|
+
|
|
1966
|
+
// src/internal/provider/fallback.tsx
|
|
1967
|
+
var import_react8 = require("react");
|
|
1968
|
+
var Logix8 = __toESM(require("@logixjs/core"), 1);
|
|
1969
|
+
|
|
1970
|
+
// src/internal/provider/docs.ts
|
|
1971
|
+
var LOGIX_DOCS_PREFIX_ENV = "LOGIX_DOCS_PREFIX";
|
|
1972
|
+
var stripTrailingSlashes = (value) => value.replace(/\/+$/, "");
|
|
1973
|
+
var ensureLeadingSlash = (value) => value.startsWith("/") ? value : `/${value}`;
|
|
1974
|
+
var getProcessEnvString = (key) => {
|
|
1975
|
+
try {
|
|
1976
|
+
const env = globalThis?.process?.env;
|
|
1977
|
+
const value = env?.[key];
|
|
1978
|
+
return typeof value === "string" ? value : void 0;
|
|
1979
|
+
} catch {
|
|
1980
|
+
return void 0;
|
|
1981
|
+
}
|
|
1982
|
+
};
|
|
1983
|
+
var getLocationOrigin = () => {
|
|
1984
|
+
try {
|
|
1985
|
+
const origin = globalThis?.location?.origin;
|
|
1986
|
+
return typeof origin === "string" && origin.length > 0 ? origin : void 0;
|
|
1987
|
+
} catch {
|
|
1988
|
+
return void 0;
|
|
1989
|
+
}
|
|
1990
|
+
};
|
|
1991
|
+
var getDocsRootPrefix = () => {
|
|
1992
|
+
const raw = getProcessEnvString(LOGIX_DOCS_PREFIX_ENV);
|
|
1993
|
+
const fromEnv = raw ? stripTrailingSlashes(raw.trim()) : void 0;
|
|
1994
|
+
if (fromEnv && fromEnv.length > 0) {
|
|
1995
|
+
if (/^https?:\/\//i.test(fromEnv)) {
|
|
1996
|
+
return fromEnv;
|
|
1997
|
+
}
|
|
1998
|
+
const origin2 = getLocationOrigin();
|
|
1999
|
+
if (origin2) {
|
|
2000
|
+
return stripTrailingSlashes(`${origin2}${ensureLeadingSlash(fromEnv)}`);
|
|
2001
|
+
}
|
|
2002
|
+
return fromEnv;
|
|
2003
|
+
}
|
|
2004
|
+
const origin = getLocationOrigin();
|
|
2005
|
+
return origin ? `${origin}/zh/docs` : void 0;
|
|
2006
|
+
};
|
|
2007
|
+
var resolveLogixDocsUrl = (docsPath) => {
|
|
2008
|
+
const docsRoot = getDocsRootPrefix();
|
|
2009
|
+
const path = ensureLeadingSlash(docsPath);
|
|
2010
|
+
if (docsRoot) {
|
|
2011
|
+
return `${stripTrailingSlashes(docsRoot)}${path}`;
|
|
2012
|
+
}
|
|
2013
|
+
return path;
|
|
2014
|
+
};
|
|
2015
|
+
var getFallbackWarningDocsUrl = () => resolveLogixDocsUrl("/guide/essentials/react-integration");
|
|
2016
|
+
var getFallbackWarningDocsPrefixEnv = () => LOGIX_DOCS_PREFIX_ENV;
|
|
2017
|
+
|
|
2018
|
+
// src/internal/provider/fallback.tsx
|
|
2019
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
2020
|
+
var FALLBACK_WARNED_BY_RUNTIME = /* @__PURE__ */ new WeakMap();
|
|
2021
|
+
var DEFAULT_FALLBACK_WARN_THRESHOLD_MS = 100;
|
|
2022
|
+
var DEFAULT_FALLBACK_FLASH_HINT_MIN_MS = 16;
|
|
2023
|
+
var DefaultRuntimeFallback = ({ phase, policyMode }) => {
|
|
2024
|
+
const [elapsedMs, setElapsedMs] = (0, import_react8.useState)(0);
|
|
2025
|
+
(0, import_react8.useEffect)(() => {
|
|
2026
|
+
const start = performance.now();
|
|
2027
|
+
const interval = setInterval(() => {
|
|
2028
|
+
setElapsedMs(Math.round(performance.now() - start));
|
|
2029
|
+
}, 100);
|
|
2030
|
+
return () => {
|
|
2031
|
+
clearInterval(interval);
|
|
2032
|
+
};
|
|
2033
|
+
}, []);
|
|
2034
|
+
const message = phase === "provider.gating" ? "Logix \u8FD0\u884C\u65F6\u51C6\u5907\u4E2D\u2026" : "Logix \u6A21\u5757\u89E3\u6790\u4E2D\u2026";
|
|
2035
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
2036
|
+
"div",
|
|
2037
|
+
{
|
|
2038
|
+
style: {
|
|
2039
|
+
padding: 12,
|
|
2040
|
+
fontSize: 13,
|
|
2041
|
+
lineHeight: 1.4,
|
|
2042
|
+
opacity: 0.85,
|
|
2043
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
|
|
2044
|
+
},
|
|
2045
|
+
children: [
|
|
2046
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
2047
|
+
message,
|
|
2048
|
+
" ",
|
|
2049
|
+
elapsedMs,
|
|
2050
|
+
"ms"
|
|
2051
|
+
] }),
|
|
2052
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: 6, opacity: 0.8 }, children: [
|
|
2053
|
+
"policy.mode=",
|
|
2054
|
+
policyMode,
|
|
2055
|
+
"\uFF08\u60F3\u201C\u65E0\u7B49\u5F85\u201D\u2192 sync\uFF1B\u60F3\u201C\u5C11\u95EA\u70C1\u201D\u2192 defer+preload\uFF09"
|
|
2056
|
+
] })
|
|
2057
|
+
]
|
|
2058
|
+
}
|
|
2059
|
+
);
|
|
2060
|
+
};
|
|
2061
|
+
var resolveRuntimeProviderFallback = (args) => {
|
|
2062
|
+
if (args.fallback !== void 0) {
|
|
2063
|
+
return args.fallback;
|
|
2064
|
+
}
|
|
2065
|
+
if (!(0, import_Env.isDevEnv)()) {
|
|
2066
|
+
return null;
|
|
2067
|
+
}
|
|
2068
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultRuntimeFallback, { phase: args.phase, policyMode: args.policyMode });
|
|
2069
|
+
};
|
|
2070
|
+
var recordFallbackDuration = (args) => {
|
|
2071
|
+
if (!(0, import_Env.isDevEnv)() && !Logix8.Debug.isDevtoolsEnabled()) {
|
|
2072
|
+
return;
|
|
2073
|
+
}
|
|
2074
|
+
void args.runtime.runPromise(
|
|
2075
|
+
Logix8.Debug.record({
|
|
2076
|
+
type: "trace:react.fallback.duration",
|
|
2077
|
+
data: {
|
|
2078
|
+
phase: args.phase,
|
|
2079
|
+
policyMode: args.policyMode,
|
|
2080
|
+
durationMs: Math.round(args.durationMs * 100) / 100,
|
|
2081
|
+
blockers: args.blockers
|
|
2082
|
+
}
|
|
2083
|
+
})
|
|
2084
|
+
).catch(() => {
|
|
2085
|
+
});
|
|
2086
|
+
};
|
|
2087
|
+
var warnFallbackDuration = (args) => {
|
|
2088
|
+
if (!(0, import_Env.isDevEnv)()) {
|
|
2089
|
+
return;
|
|
2090
|
+
}
|
|
2091
|
+
const warnThresholdMs = DEFAULT_FALLBACK_WARN_THRESHOLD_MS;
|
|
2092
|
+
const isVisibleLong = args.durationMs >= warnThresholdMs;
|
|
2093
|
+
const isFlashHint = args.phase === "react.suspense" && args.policyMode !== "sync" && args.durationMs >= DEFAULT_FALLBACK_FLASH_HINT_MIN_MS && args.durationMs < warnThresholdMs;
|
|
2094
|
+
if (!isVisibleLong && !isFlashHint) {
|
|
2095
|
+
return;
|
|
2096
|
+
}
|
|
2097
|
+
const runtimeKey = args.runtime;
|
|
2098
|
+
const warned = FALLBACK_WARNED_BY_RUNTIME.get(runtimeKey) ?? /* @__PURE__ */ new Set();
|
|
2099
|
+
FALLBACK_WARNED_BY_RUNTIME.set(runtimeKey, warned);
|
|
2100
|
+
const kind = isVisibleLong ? "visible" : "flash";
|
|
2101
|
+
const dedupeKey = `${kind}::${args.phase}::${args.policyMode}::${args.blockers ?? "none"}`;
|
|
2102
|
+
if (warned.has(dedupeKey)) {
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
2105
|
+
warned.add(dedupeKey);
|
|
2106
|
+
const docs = `Docs: ${getFallbackWarningDocsUrl()} (override via ${getFallbackWarningDocsPrefixEnv()})`;
|
|
2107
|
+
const header = isVisibleLong ? "[Logix][React] Fallback visible" : "[Logix][React] Suspense fallback resolved quickly";
|
|
2108
|
+
const hint = (() => {
|
|
2109
|
+
if (isVisibleLong) {
|
|
2110
|
+
if (args.phase === "provider.gating") {
|
|
2111
|
+
return args.policyMode === "sync" ? 'Hint: You are using policy.mode="sync", but the provider is still waiting for dependencies (layer/config). Consider using "suspend"/"defer" (default UX), and/or make your layer/config ready earlier.' : "Hint: RuntimeProvider is still waiting for dependencies (layer/config/preload). Provide a fallback, use defer+preload, or switch to sync (deterministic, but render-blocking).";
|
|
2112
|
+
}
|
|
2113
|
+
return 'Hint: Suspense fallback is active (module resolve). If you prefer fewer fallbacks, use defer+preload; if you prefer \u201Cno waiting\u201D, switch to policy.mode="sync" (moves the cost to render-time sync blocking).';
|
|
2114
|
+
}
|
|
2115
|
+
return 'Hint: This fallback is short. If you want to eliminate the flicker, consider policy.mode="sync" (but it may introduce render-time sync blocking).';
|
|
2116
|
+
})();
|
|
2117
|
+
const example = (() => {
|
|
2118
|
+
if (isFlashHint) {
|
|
2119
|
+
return 'Example: <RuntimeProvider policy={{ mode: "sync" }} fallback={<Loading />}>\u2026</RuntimeProvider>';
|
|
2120
|
+
}
|
|
2121
|
+
return args.phase === "provider.gating" ? 'Example: <RuntimeProvider policy={{ mode: "defer", preload: [MyImpl] }} fallback={<Loading />}>\u2026</RuntimeProvider>' : 'Example: <RuntimeProvider policy={{ mode: "sync" }} fallback={<Loading />}>\u2026</RuntimeProvider>';
|
|
2122
|
+
})();
|
|
2123
|
+
const log = isVisibleLong ? console.warn : console.info;
|
|
2124
|
+
log(
|
|
2125
|
+
header,
|
|
2126
|
+
`(${Math.round(args.durationMs)}ms)`,
|
|
2127
|
+
"\n",
|
|
2128
|
+
`phase=${args.phase}`,
|
|
2129
|
+
"\n",
|
|
2130
|
+
`policy.mode=${args.policyMode}`,
|
|
2131
|
+
args.blockers ? `
|
|
2132
|
+
blockers=${args.blockers}` : "",
|
|
2133
|
+
"\n",
|
|
2134
|
+
hint,
|
|
2135
|
+
"\n",
|
|
2136
|
+
example,
|
|
2137
|
+
"\n",
|
|
2138
|
+
docs
|
|
2139
|
+
);
|
|
2140
|
+
};
|
|
2141
|
+
var FallbackProbeEnabled = ({ runtime, phase, policyMode, blockers, children }) => {
|
|
2142
|
+
(0, import_react8.useEffect)(() => {
|
|
2143
|
+
const startedAt = performance.now();
|
|
2144
|
+
return () => {
|
|
2145
|
+
const durationMs = performance.now() - startedAt;
|
|
2146
|
+
recordFallbackDuration({ runtime, phase, policyMode, durationMs, blockers });
|
|
2147
|
+
warnFallbackDuration({ runtime, phase, policyMode, durationMs, blockers });
|
|
2148
|
+
};
|
|
2149
|
+
}, [runtime, phase, policyMode, blockers]);
|
|
2150
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
2151
|
+
};
|
|
2152
|
+
var FallbackProbeNoop = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
2153
|
+
var FallbackProbe = (props) => {
|
|
2154
|
+
const enabled = (0, import_Env.isDevEnv)() || Logix8.Debug.isDevtoolsEnabled();
|
|
2155
|
+
const Impl = enabled ? FallbackProbeEnabled : FallbackProbeNoop;
|
|
2156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Impl, { ...props });
|
|
2157
|
+
};
|
|
2158
|
+
|
|
2159
|
+
// src/internal/provider/policy.ts
|
|
2160
|
+
var DEFAULT_PRELOAD_CONCURRENCY = 5;
|
|
2161
|
+
var DEFAULT_SYNC_BUDGET_MS = 5;
|
|
2162
|
+
var DEFAULT_YIELD_STRATEGY = "microtask";
|
|
2163
|
+
var isModuleImpl2 = (handle) => Boolean(handle) && typeof handle === "object" && handle._tag === "ModuleImpl";
|
|
2164
|
+
var isModuleTag = (handle) => {
|
|
2165
|
+
if (!handle || typeof handle !== "object" && typeof handle !== "function") {
|
|
2166
|
+
return false;
|
|
2167
|
+
}
|
|
2168
|
+
const candidate = handle;
|
|
2169
|
+
return candidate._kind === "ModuleTag";
|
|
2170
|
+
};
|
|
2171
|
+
var getPreloadKeyForModuleId = (moduleId) => `preload:impl:${moduleId}`;
|
|
2172
|
+
var getPreloadKeyForTagId = (tagId) => `preload:tag:${tagId}`;
|
|
2173
|
+
var normalizeYieldPolicy = (policy) => ({
|
|
2174
|
+
strategy: policy?.strategy ?? DEFAULT_YIELD_STRATEGY,
|
|
2175
|
+
onlyWhenOverBudgetMs: policy?.onlyWhenOverBudgetMs
|
|
2176
|
+
});
|
|
2177
|
+
var normalizePreload = (preload) => {
|
|
2178
|
+
if (!preload) return null;
|
|
2179
|
+
const policy = Array.isArray(preload) ? { handles: preload } : preload;
|
|
2180
|
+
const handles = [];
|
|
2181
|
+
for (const handle of policy.handles ?? []) {
|
|
2182
|
+
if (isModuleImpl2(handle) || isModuleTag(handle)) {
|
|
2183
|
+
handles.push(handle);
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
return {
|
|
2187
|
+
handles,
|
|
2188
|
+
concurrency: Math.max(1, policy.concurrency ?? DEFAULT_PRELOAD_CONCURRENCY),
|
|
2189
|
+
yield: normalizeYieldPolicy(policy.yield)
|
|
2190
|
+
};
|
|
2191
|
+
};
|
|
2192
|
+
var resolveRuntimeProviderPolicy = (args) => {
|
|
2193
|
+
const inheritedMode = args.parentPolicy?.mode;
|
|
2194
|
+
const mode = args.policy?.mode ?? (inheritedMode !== void 0 ? inheritedMode : "suspend");
|
|
2195
|
+
const moduleResolveMode = mode === "sync" ? "sync" : "suspend";
|
|
2196
|
+
const preload = mode === "defer" ? normalizePreload(args.policy?.preload) : null;
|
|
2197
|
+
const keysByModuleId = /* @__PURE__ */ new Map();
|
|
2198
|
+
const keysByTagId = /* @__PURE__ */ new Map();
|
|
2199
|
+
if (preload) {
|
|
2200
|
+
for (const handle of preload.handles) {
|
|
2201
|
+
if (isModuleImpl2(handle)) {
|
|
2202
|
+
const moduleId = handle.module.id ?? "ModuleImpl";
|
|
2203
|
+
keysByModuleId.set(moduleId, getPreloadKeyForModuleId(moduleId));
|
|
2204
|
+
} else if (isModuleTag(handle)) {
|
|
2205
|
+
const tagId = handle.id ?? "ModuleTag";
|
|
2206
|
+
keysByTagId.set(tagId, getPreloadKeyForTagId(tagId));
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
return {
|
|
2211
|
+
mode,
|
|
2212
|
+
moduleImplMode: moduleResolveMode,
|
|
2213
|
+
moduleTagMode: moduleResolveMode,
|
|
2214
|
+
syncBudgetMs: Math.max(0, args.policy?.syncBudgetMs ?? args.parentPolicy?.syncBudgetMs ?? DEFAULT_SYNC_BUDGET_MS),
|
|
2215
|
+
yield: normalizeYieldPolicy(args.policy?.yield ?? args.parentPolicy?.yield),
|
|
2216
|
+
preload: preload ? {
|
|
2217
|
+
...preload,
|
|
2218
|
+
keysByModuleId,
|
|
2219
|
+
keysByTagId
|
|
2220
|
+
} : null
|
|
2221
|
+
};
|
|
2222
|
+
};
|
|
2223
|
+
|
|
2224
|
+
// src/internal/provider/RuntimeProvider.tsx
|
|
2225
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2226
|
+
var SYNC_CONFIG_OVER_BUDGET_BY_RUNTIME = /* @__PURE__ */ new WeakMap();
|
|
2227
|
+
var RuntimeProvider = ({
|
|
2228
|
+
layer,
|
|
2229
|
+
runtime,
|
|
2230
|
+
children,
|
|
2231
|
+
fallback,
|
|
2232
|
+
policy,
|
|
2233
|
+
onError
|
|
2234
|
+
}) => {
|
|
2235
|
+
const parent = (0, import_react9.useContext)(RuntimeContext);
|
|
2236
|
+
const baseRuntime = useRuntimeResolution(runtime, parent);
|
|
2237
|
+
const resolvedPolicy = (0, import_react9.useMemo)(
|
|
2238
|
+
() => resolveRuntimeProviderPolicy({
|
|
2239
|
+
policy,
|
|
2240
|
+
parentPolicy: parent?.policy ?? null
|
|
2241
|
+
}),
|
|
2242
|
+
[policy, parent?.policy]
|
|
2243
|
+
);
|
|
2244
|
+
const onErrorRef = import_react9.default.useRef(onError);
|
|
2245
|
+
onErrorRef.current = onError;
|
|
2246
|
+
const { binding: layerBinding } = useLayerBinding(baseRuntime, layer, Boolean(layer), onErrorRef.current);
|
|
2247
|
+
const onErrorSink = (0, import_react9.useMemo)(() => {
|
|
2248
|
+
if (!onError) return null;
|
|
2249
|
+
const sink = {
|
|
2250
|
+
record: (event) => {
|
|
2251
|
+
const handler = onErrorRef.current;
|
|
2252
|
+
if (!handler) {
|
|
2253
|
+
return import_effect10.Effect.void;
|
|
2254
|
+
}
|
|
2255
|
+
if (event.type === "lifecycle:error") {
|
|
2256
|
+
return handler(event.cause, {
|
|
2257
|
+
source: "provider",
|
|
2258
|
+
phase: "debug.lifecycle_error",
|
|
2259
|
+
moduleId: event.moduleId,
|
|
2260
|
+
instanceId: event.instanceId,
|
|
2261
|
+
runtimeLabel: event.runtimeLabel
|
|
2262
|
+
}).pipe(import_effect10.Effect.catchAllCause(() => import_effect10.Effect.void));
|
|
2263
|
+
}
|
|
2264
|
+
if (event.type === "diagnostic" && event.severity === "error") {
|
|
2265
|
+
return handler(
|
|
2266
|
+
import_effect10.Cause.fail({
|
|
2267
|
+
code: event.code,
|
|
2268
|
+
message: event.message,
|
|
2269
|
+
hint: event.hint
|
|
2270
|
+
}),
|
|
2271
|
+
{
|
|
2272
|
+
source: "provider",
|
|
2273
|
+
phase: "debug.diagnostic_error",
|
|
2274
|
+
code: event.code,
|
|
2275
|
+
message: event.message,
|
|
2276
|
+
hint: event.hint,
|
|
2277
|
+
moduleId: event.moduleId,
|
|
2278
|
+
instanceId: event.instanceId,
|
|
2279
|
+
runtimeLabel: event.runtimeLabel
|
|
2280
|
+
}
|
|
2281
|
+
).pipe(import_effect10.Effect.catchAllCause(() => import_effect10.Effect.void));
|
|
2282
|
+
}
|
|
2283
|
+
return import_effect10.Effect.void;
|
|
2284
|
+
}
|
|
2285
|
+
};
|
|
2286
|
+
return sink;
|
|
2287
|
+
}, [Boolean(onError)]);
|
|
2288
|
+
const inheritedDebugSinks = (0, import_react9.useMemo)(() => {
|
|
2289
|
+
if (!onErrorSink) {
|
|
2290
|
+
return [];
|
|
2291
|
+
}
|
|
2292
|
+
if (layerBinding) {
|
|
2293
|
+
return layerBinding.debugSinks;
|
|
2294
|
+
}
|
|
2295
|
+
try {
|
|
2296
|
+
return baseRuntime.runSync(
|
|
2297
|
+
import_effect10.FiberRef.get(Logix9.Debug.internal.currentDebugSinks)
|
|
2298
|
+
);
|
|
2299
|
+
} catch {
|
|
2300
|
+
return [];
|
|
2301
|
+
}
|
|
2302
|
+
}, [baseRuntime, layerBinding, onErrorSink]);
|
|
2303
|
+
const runtimeWithBindings = (0, import_react9.useMemo)(
|
|
2304
|
+
() => layerBinding || onErrorSink ? createRuntimeAdapter(
|
|
2305
|
+
baseRuntime,
|
|
2306
|
+
layerBinding ? [layerBinding.context] : [],
|
|
2307
|
+
layerBinding ? [layerBinding.scope] : [],
|
|
2308
|
+
layerBinding ? [layerBinding.loggers] : [],
|
|
2309
|
+
layerBinding ? [layerBinding.logLevel] : [],
|
|
2310
|
+
[
|
|
2311
|
+
onErrorSink ? [onErrorSink, ...inheritedDebugSinks] : layerBinding ? layerBinding.debugSinks : []
|
|
2312
|
+
]
|
|
2313
|
+
) : baseRuntime,
|
|
2314
|
+
[baseRuntime, inheritedDebugSinks, layerBinding, onErrorSink]
|
|
2315
|
+
);
|
|
2316
|
+
const didReportSyncConfigSnapshotRef = import_react9.default.useRef(false);
|
|
2317
|
+
const [configState, setConfigState] = (0, import_react9.useState)(() => {
|
|
2318
|
+
const budgetMs = resolvedPolicy.syncBudgetMs;
|
|
2319
|
+
if (budgetMs <= 0) {
|
|
2320
|
+
return { snapshot: DEFAULT_CONFIG_SNAPSHOT, version: 1, loaded: false, loadMode: "none" };
|
|
2321
|
+
}
|
|
2322
|
+
if (SYNC_CONFIG_OVER_BUDGET_BY_RUNTIME.has(baseRuntime)) {
|
|
2323
|
+
return { snapshot: DEFAULT_CONFIG_SNAPSHOT, version: 1, loaded: false, loadMode: "none" };
|
|
2324
|
+
}
|
|
2325
|
+
const startedAt = performance.now();
|
|
2326
|
+
try {
|
|
2327
|
+
const snapshot = runtimeWithBindings.runSync(
|
|
2328
|
+
ReactRuntimeConfigSnapshot.load
|
|
2329
|
+
);
|
|
2330
|
+
const durationMs = performance.now() - startedAt;
|
|
2331
|
+
const overBudget = durationMs > budgetMs;
|
|
2332
|
+
if (overBudget) {
|
|
2333
|
+
SYNC_CONFIG_OVER_BUDGET_BY_RUNTIME.set(baseRuntime, true);
|
|
2334
|
+
}
|
|
2335
|
+
return {
|
|
2336
|
+
snapshot,
|
|
2337
|
+
version: 1,
|
|
2338
|
+
loaded: !overBudget,
|
|
2339
|
+
loadMode: "sync",
|
|
2340
|
+
syncDurationMs: durationMs,
|
|
2341
|
+
syncOverBudget: overBudget
|
|
2342
|
+
};
|
|
2343
|
+
} catch {
|
|
2344
|
+
return { snapshot: DEFAULT_CONFIG_SNAPSHOT, version: 1, loaded: false, loadMode: "none" };
|
|
2345
|
+
}
|
|
2346
|
+
});
|
|
2347
|
+
(0, import_react9.useEffect)(() => {
|
|
2348
|
+
if (configState.loadMode !== "sync") {
|
|
2349
|
+
return;
|
|
2350
|
+
}
|
|
2351
|
+
if (didReportSyncConfigSnapshotRef.current) {
|
|
2352
|
+
return;
|
|
2353
|
+
}
|
|
2354
|
+
didReportSyncConfigSnapshotRef.current = true;
|
|
2355
|
+
void runtimeWithBindings.runPromise(
|
|
2356
|
+
Logix9.Debug.record({
|
|
2357
|
+
type: "trace:react.runtime.config.snapshot",
|
|
2358
|
+
data: {
|
|
2359
|
+
source: configState.snapshot.source,
|
|
2360
|
+
mode: "sync",
|
|
2361
|
+
durationMs: configState.syncDurationMs !== void 0 ? Math.round(configState.syncDurationMs * 100) / 100 : void 0,
|
|
2362
|
+
syncBudgetMs: resolvedPolicy.syncBudgetMs,
|
|
2363
|
+
overBudget: Boolean(configState.syncOverBudget)
|
|
2364
|
+
}
|
|
2365
|
+
})
|
|
2366
|
+
).catch(() => {
|
|
2367
|
+
});
|
|
2368
|
+
}, [configState, resolvedPolicy.syncBudgetMs, runtimeWithBindings]);
|
|
2369
|
+
(0, import_react9.useEffect)(() => {
|
|
2370
|
+
let cancelled = false;
|
|
2371
|
+
runtimeWithBindings.runPromise(ReactRuntimeConfigSnapshot.load).then((snapshot) => {
|
|
2372
|
+
if (cancelled) return;
|
|
2373
|
+
setConfigState((prev) => {
|
|
2374
|
+
const sameSnapshot = prev.snapshot.gcTime === snapshot.gcTime && prev.snapshot.initTimeoutMs === snapshot.initTimeoutMs && prev.snapshot.lowPriorityDelayMs === snapshot.lowPriorityDelayMs && prev.snapshot.lowPriorityMaxDelayMs === snapshot.lowPriorityMaxDelayMs && prev.snapshot.source === snapshot.source;
|
|
2375
|
+
if (sameSnapshot && prev.loaded) {
|
|
2376
|
+
return prev;
|
|
2377
|
+
}
|
|
2378
|
+
const cacheCriticalChanged = prev.snapshot.gcTime !== snapshot.gcTime;
|
|
2379
|
+
return {
|
|
2380
|
+
snapshot,
|
|
2381
|
+
version: cacheCriticalChanged ? prev.version + 1 : prev.version,
|
|
2382
|
+
loaded: true,
|
|
2383
|
+
loadMode: "async"
|
|
2384
|
+
};
|
|
2385
|
+
});
|
|
2386
|
+
void runtimeWithBindings.runPromise(
|
|
2387
|
+
Logix9.Debug.record({
|
|
2388
|
+
type: "trace:react.runtime.config.snapshot",
|
|
2389
|
+
data: {
|
|
2390
|
+
source: snapshot.source,
|
|
2391
|
+
mode: "async"
|
|
2392
|
+
}
|
|
2393
|
+
})
|
|
2394
|
+
).catch(() => {
|
|
2395
|
+
});
|
|
2396
|
+
}).catch((error) => {
|
|
2397
|
+
if (cancelled) return;
|
|
2398
|
+
console.debug("[RuntimeProvider] Failed to load React runtime config snapshot, fallback to default.", error);
|
|
2399
|
+
setConfigState((prev) => ({
|
|
2400
|
+
snapshot: DEFAULT_CONFIG_SNAPSHOT,
|
|
2401
|
+
version: prev.version,
|
|
2402
|
+
loaded: true,
|
|
2403
|
+
loadMode: "async"
|
|
2404
|
+
}));
|
|
2405
|
+
});
|
|
2406
|
+
return () => {
|
|
2407
|
+
cancelled = true;
|
|
2408
|
+
};
|
|
2409
|
+
}, [runtimeWithBindings]);
|
|
2410
|
+
const contextValue = (0, import_react9.useMemo)(
|
|
2411
|
+
() => ({
|
|
2412
|
+
runtime: runtimeWithBindings,
|
|
2413
|
+
reactConfigSnapshot: configState.snapshot,
|
|
2414
|
+
configVersion: configState.version,
|
|
2415
|
+
policy: resolvedPolicy
|
|
2416
|
+
}),
|
|
2417
|
+
[runtimeWithBindings, configState, resolvedPolicy]
|
|
2418
|
+
);
|
|
2419
|
+
const isLayerReady = !layer || layerBinding !== null;
|
|
2420
|
+
const isConfigReady = configState.loaded;
|
|
2421
|
+
const resolveFallback = (phase) => {
|
|
2422
|
+
return resolveRuntimeProviderFallback({ fallback, phase, policyMode: resolvedPolicy.mode });
|
|
2423
|
+
};
|
|
2424
|
+
const [deferReady, setDeferReady] = (0, import_react9.useState)(false);
|
|
2425
|
+
(0, import_react9.useEffect)(() => {
|
|
2426
|
+
if (resolvedPolicy.mode !== "defer") {
|
|
2427
|
+
setDeferReady(false);
|
|
2428
|
+
return;
|
|
2429
|
+
}
|
|
2430
|
+
setDeferReady(false);
|
|
2431
|
+
}, [resolvedPolicy.mode]);
|
|
2432
|
+
const preloadCancelsRef = import_react9.default.useRef(null);
|
|
2433
|
+
(0, import_react9.useEffect)(() => {
|
|
2434
|
+
if (resolvedPolicy.mode !== "defer") {
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
setDeferReady(false);
|
|
2438
|
+
if (!resolvedPolicy.preload) {
|
|
2439
|
+
setDeferReady(true);
|
|
2440
|
+
return;
|
|
2441
|
+
}
|
|
2442
|
+
if (!isLayerReady || !isConfigReady) {
|
|
2443
|
+
return;
|
|
2444
|
+
}
|
|
2445
|
+
let cancelled = false;
|
|
2446
|
+
const cache = getModuleCache(runtimeWithBindings, configState.snapshot, configState.version);
|
|
2447
|
+
const preloadHandles = resolvedPolicy.preload.handles;
|
|
2448
|
+
if (preloadHandles.length === 0) {
|
|
2449
|
+
setDeferReady(true);
|
|
2450
|
+
return;
|
|
2451
|
+
}
|
|
2452
|
+
const concurrency = Math.max(1, resolvedPolicy.preload.concurrency ?? DEFAULT_PRELOAD_CONCURRENCY);
|
|
2453
|
+
const allCancels = /* @__PURE__ */ new Set();
|
|
2454
|
+
preloadCancelsRef.current = allCancels;
|
|
2455
|
+
const run = async () => {
|
|
2456
|
+
const queue = preloadHandles.slice();
|
|
2457
|
+
const runOne = async (handle) => {
|
|
2458
|
+
if (cancelled) return;
|
|
2459
|
+
const startedAt = performance.now();
|
|
2460
|
+
if (handle?._tag === "ModuleImpl") {
|
|
2461
|
+
const moduleId = handle.module?.id ?? "ModuleImpl";
|
|
2462
|
+
const key2 = resolvedPolicy.preload.keysByModuleId.get(moduleId) ?? getPreloadKeyForModuleId(moduleId);
|
|
2463
|
+
const factory2 = (scope) => import_effect10.Layer.buildWithScope(handle.layer, scope).pipe(
|
|
2464
|
+
import_effect10.Effect.map((context) => import_effect10.Context.get(context, handle.module))
|
|
2465
|
+
);
|
|
2466
|
+
const op2 = cache.preload(key2, factory2, {
|
|
2467
|
+
ownerId: moduleId,
|
|
2468
|
+
yield: resolvedPolicy.preload.yield,
|
|
2469
|
+
entrypoint: "react.runtime.preload",
|
|
2470
|
+
policyMode: "defer"
|
|
2471
|
+
});
|
|
2472
|
+
allCancels.add(op2.cancel);
|
|
2473
|
+
await op2.promise;
|
|
2474
|
+
const durationMs2 = performance.now() - startedAt;
|
|
2475
|
+
void runtimeWithBindings.runPromise(
|
|
2476
|
+
Logix9.Debug.record({
|
|
2477
|
+
type: "trace:react.module.preload",
|
|
2478
|
+
moduleId,
|
|
2479
|
+
data: {
|
|
2480
|
+
mode: "defer",
|
|
2481
|
+
handleKind: "ModuleImpl",
|
|
2482
|
+
key: key2,
|
|
2483
|
+
durationMs: Math.round(durationMs2 * 100) / 100,
|
|
2484
|
+
concurrency,
|
|
2485
|
+
yieldStrategy: resolvedPolicy.preload.yield.strategy,
|
|
2486
|
+
yieldOnlyWhenOverBudgetMs: resolvedPolicy.preload.yield.onlyWhenOverBudgetMs
|
|
2487
|
+
}
|
|
2488
|
+
})
|
|
2489
|
+
).catch(() => {
|
|
2490
|
+
});
|
|
2491
|
+
return;
|
|
2492
|
+
}
|
|
2493
|
+
const tagId = handle.id ?? "ModuleTag";
|
|
2494
|
+
const key = resolvedPolicy.preload.keysByTagId.get(tagId) ?? getPreloadKeyForTagId(tagId);
|
|
2495
|
+
const factory = (scope) => handle.pipe(
|
|
2496
|
+
import_effect10.Scope.extend(scope)
|
|
2497
|
+
);
|
|
2498
|
+
const op = cache.preload(key, factory, {
|
|
2499
|
+
ownerId: tagId,
|
|
2500
|
+
yield: resolvedPolicy.preload.yield,
|
|
2501
|
+
entrypoint: "react.runtime.preload",
|
|
2502
|
+
policyMode: "defer"
|
|
2503
|
+
});
|
|
2504
|
+
allCancels.add(op.cancel);
|
|
2505
|
+
await op.promise;
|
|
2506
|
+
const durationMs = performance.now() - startedAt;
|
|
2507
|
+
void runtimeWithBindings.runPromise(
|
|
2508
|
+
Logix9.Debug.record({
|
|
2509
|
+
type: "trace:react.module.preload",
|
|
2510
|
+
data: {
|
|
2511
|
+
mode: "defer",
|
|
2512
|
+
handleKind: "ModuleTag",
|
|
2513
|
+
tokenId: tagId,
|
|
2514
|
+
key,
|
|
2515
|
+
durationMs: Math.round(durationMs * 100) / 100,
|
|
2516
|
+
concurrency,
|
|
2517
|
+
yieldStrategy: resolvedPolicy.preload.yield.strategy,
|
|
2518
|
+
yieldOnlyWhenOverBudgetMs: resolvedPolicy.preload.yield.onlyWhenOverBudgetMs
|
|
2519
|
+
}
|
|
2520
|
+
})
|
|
2521
|
+
).catch(() => {
|
|
2522
|
+
});
|
|
2523
|
+
};
|
|
2524
|
+
const workers = Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
|
|
2525
|
+
while (!cancelled) {
|
|
2526
|
+
const next = queue.shift();
|
|
2527
|
+
if (!next) return;
|
|
2528
|
+
await runOne(next);
|
|
2529
|
+
}
|
|
2530
|
+
});
|
|
2531
|
+
await Promise.all(workers);
|
|
2532
|
+
};
|
|
2533
|
+
run().then(() => {
|
|
2534
|
+
if (cancelled) return;
|
|
2535
|
+
setDeferReady(true);
|
|
2536
|
+
}).catch((error) => {
|
|
2537
|
+
if (cancelled) return;
|
|
2538
|
+
if (onErrorRef.current) {
|
|
2539
|
+
runtimeWithBindings.runFork(
|
|
2540
|
+
onErrorRef.current(import_effect10.Cause.die(error), { source: "provider", phase: "provider.layer.build" }).pipe(import_effect10.Effect.catchAllCause(() => import_effect10.Effect.void))
|
|
2541
|
+
);
|
|
2542
|
+
}
|
|
2543
|
+
setDeferReady(true);
|
|
2544
|
+
});
|
|
2545
|
+
return () => {
|
|
2546
|
+
cancelled = true;
|
|
2547
|
+
preloadCancelsRef.current = null;
|
|
2548
|
+
for (const cancel of allCancels) cancel();
|
|
2549
|
+
};
|
|
2550
|
+
}, [resolvedPolicy, isLayerReady, isConfigReady, runtimeWithBindings, configState, onErrorRef]);
|
|
2551
|
+
(0, import_react9.useEffect)(() => {
|
|
2552
|
+
if (resolvedPolicy.mode !== "defer" || !deferReady) {
|
|
2553
|
+
return;
|
|
2554
|
+
}
|
|
2555
|
+
const cancels = preloadCancelsRef.current;
|
|
2556
|
+
if (!cancels || cancels.size === 0) {
|
|
2557
|
+
return;
|
|
2558
|
+
}
|
|
2559
|
+
preloadCancelsRef.current = null;
|
|
2560
|
+
const list = Array.from(cancels);
|
|
2561
|
+
let released = false;
|
|
2562
|
+
const release = () => {
|
|
2563
|
+
if (released) return;
|
|
2564
|
+
released = true;
|
|
2565
|
+
for (const cancel of list) cancel();
|
|
2566
|
+
};
|
|
2567
|
+
const timeout = setTimeout(release, 0);
|
|
2568
|
+
return () => {
|
|
2569
|
+
clearTimeout(timeout);
|
|
2570
|
+
release();
|
|
2571
|
+
};
|
|
2572
|
+
}, [resolvedPolicy.mode, deferReady]);
|
|
2573
|
+
const isReady = isLayerReady && isConfigReady && (resolvedPolicy.mode !== "defer" || deferReady);
|
|
2574
|
+
if (!isReady) {
|
|
2575
|
+
const blockersList = [
|
|
2576
|
+
isLayerReady ? null : "layer",
|
|
2577
|
+
isConfigReady ? null : "config",
|
|
2578
|
+
resolvedPolicy.mode !== "defer" || deferReady ? null : "preload"
|
|
2579
|
+
].filter((x) => x !== null);
|
|
2580
|
+
const blockers = blockersList.length > 0 ? blockersList.join("+") : void 0;
|
|
2581
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2582
|
+
FallbackProbe,
|
|
2583
|
+
{
|
|
2584
|
+
runtime: runtimeWithBindings,
|
|
2585
|
+
phase: "provider.gating",
|
|
2586
|
+
policyMode: resolvedPolicy.mode,
|
|
2587
|
+
blockers,
|
|
2588
|
+
children: resolveFallback("provider.gating")
|
|
2589
|
+
}
|
|
2590
|
+
);
|
|
2591
|
+
}
|
|
2592
|
+
const content = resolvedPolicy.mode === "sync" ? children : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2593
|
+
import_react9.default.Suspense,
|
|
2594
|
+
{
|
|
2595
|
+
fallback: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FallbackProbe, { runtime: runtimeWithBindings, phase: "react.suspense", policyMode: resolvedPolicy.mode, children: resolveFallback("react.suspense") }),
|
|
2596
|
+
children
|
|
2597
|
+
}
|
|
2598
|
+
);
|
|
2599
|
+
return import_react9.default.createElement(RuntimeContext.Provider, { value: contextValue }, content);
|
|
2600
|
+
};
|
|
2601
|
+
var useRuntimeResolution = (runtimeProp, parent) => {
|
|
2602
|
+
const baseRuntime = runtimeProp ?? parent?.runtime;
|
|
2603
|
+
if (!baseRuntime) {
|
|
2604
|
+
throw new Error(
|
|
2605
|
+
"[RuntimeProvider] Missing runtime.\n\nFix:\n- Provide `runtime` prop: <RuntimeProvider runtime={runtime}>...\n- Or nest under an ancestor RuntimeProvider that provides `runtime`.\n"
|
|
2606
|
+
);
|
|
2607
|
+
}
|
|
2608
|
+
return baseRuntime;
|
|
2609
|
+
};
|
|
2610
|
+
|
|
2611
|
+
// src/ModuleScope.ts
|
|
2612
|
+
var makeModuleScope = (handle, defaults) => {
|
|
2613
|
+
const Context5 = import_react10.default.createContext(null);
|
|
2614
|
+
const toUseModuleOptions = (options) => {
|
|
2615
|
+
const { scopeId, ...rest } = options;
|
|
2616
|
+
return scopeId != null ? { ...rest, key: scopeId } : rest;
|
|
2617
|
+
};
|
|
2618
|
+
const getRegistryOrThrow = (runtime, where) => {
|
|
2619
|
+
try {
|
|
2620
|
+
const registry = runtime.runSync(Logix10.ScopeRegistry.ScopeRegistryTag);
|
|
2621
|
+
if (!registry) {
|
|
2622
|
+
throw new Error("ScopeRegistry service is undefined");
|
|
2623
|
+
}
|
|
2624
|
+
return registry;
|
|
2625
|
+
} catch {
|
|
2626
|
+
throw new Error(
|
|
2627
|
+
`${where} Missing Logix.ScopeRegistry in current runtime. If you are using Logix.Runtime.make, it should be provided by default. If you are using ManagedRuntime.make, include Logix.ScopeRegistry.layer() in your Layer.`
|
|
2628
|
+
);
|
|
2629
|
+
}
|
|
2630
|
+
};
|
|
2631
|
+
const moduleToken = Logix10.Module.hasImpl(handle) ? handle.tag : handle.module;
|
|
2632
|
+
const Provider = ({ children, options }) => {
|
|
2633
|
+
const runtime = useRuntime();
|
|
2634
|
+
const merged = defaults || options ? { ...defaults ?? {}, ...options ?? {} } : void 0;
|
|
2635
|
+
const ref = merged ? useModule(handle, toUseModuleOptions(merged)) : useModule(handle);
|
|
2636
|
+
const scopeId = merged?.scopeId;
|
|
2637
|
+
import_react10.default.useEffect(() => {
|
|
2638
|
+
if (!scopeId) return;
|
|
2639
|
+
const registry = getRegistryOrThrow(runtime, "[ModuleScope]");
|
|
2640
|
+
const leaseRuntime = registry.register(scopeId, Logix10.ScopeRegistry.ScopedRuntimeTag, runtime);
|
|
2641
|
+
const leaseModule = registry.register(scopeId, moduleToken, ref.runtime);
|
|
2642
|
+
return () => {
|
|
2643
|
+
leaseModule.release();
|
|
2644
|
+
leaseRuntime.release();
|
|
2645
|
+
};
|
|
2646
|
+
}, [runtime, scopeId, ref.runtime]);
|
|
2647
|
+
return import_react10.default.createElement(Context5.Provider, { value: ref }, children);
|
|
2648
|
+
};
|
|
2649
|
+
const use = () => {
|
|
2650
|
+
const ref = import_react10.default.useContext(Context5);
|
|
2651
|
+
if (!ref) {
|
|
2652
|
+
throw new Error("[ModuleScope] Provider not found");
|
|
2653
|
+
}
|
|
2654
|
+
return ref;
|
|
2655
|
+
};
|
|
2656
|
+
const useImported = (module2) => {
|
|
2657
|
+
const host = use();
|
|
2658
|
+
return host.imports.get(module2);
|
|
2659
|
+
};
|
|
2660
|
+
const Bridge = ({ scopeId, children }) => {
|
|
2661
|
+
const runtime = useRuntime();
|
|
2662
|
+
const registry = getRegistryOrThrow(runtime, "[ModuleScope.Bridge]");
|
|
2663
|
+
const scopedRuntime = registry.get(scopeId, Logix10.ScopeRegistry.ScopedRuntimeTag);
|
|
2664
|
+
const moduleRuntime = registry.get(
|
|
2665
|
+
scopeId,
|
|
2666
|
+
moduleToken
|
|
2667
|
+
);
|
|
2668
|
+
if (!scopedRuntime || !moduleRuntime) {
|
|
2669
|
+
throw new Error(
|
|
2670
|
+
`[ModuleScope.Bridge] Scope "${scopeId}" is not registered (or has been disposed). Ensure you have a corresponding <ModuleScope.Provider options={{ scopeId }}> mounted.`
|
|
2671
|
+
);
|
|
2672
|
+
}
|
|
2673
|
+
return import_react10.default.createElement(
|
|
2674
|
+
RuntimeProvider,
|
|
2675
|
+
{ runtime: scopedRuntime },
|
|
2676
|
+
import_react10.default.createElement(BridgeInner, { moduleRuntime, Context: Context5 }, children)
|
|
2677
|
+
);
|
|
2678
|
+
};
|
|
2679
|
+
const BridgeInner = ({
|
|
2680
|
+
moduleRuntime,
|
|
2681
|
+
Context: Context6,
|
|
2682
|
+
children
|
|
2683
|
+
}) => {
|
|
2684
|
+
const ref = useModule(moduleRuntime);
|
|
2685
|
+
return import_react10.default.createElement(Context6.Provider, { value: ref }, children);
|
|
2686
|
+
};
|
|
2687
|
+
return { Provider, use, useImported, Context: Context5, Bridge };
|
|
2688
|
+
};
|
|
2689
|
+
var ModuleScope = {
|
|
2690
|
+
make: makeModuleScope
|
|
2691
|
+
};
|
|
2692
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2693
|
+
0 && (module.exports = {
|
|
2694
|
+
ModuleScope
|
|
2695
|
+
});
|