@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,1618 @@
|
|
|
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/RuntimeProvider.ts
|
|
31
|
+
var RuntimeProvider_exports = {};
|
|
32
|
+
__export(RuntimeProvider_exports, {
|
|
33
|
+
RuntimeProvider: () => RuntimeProvider
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(RuntimeProvider_exports);
|
|
36
|
+
|
|
37
|
+
// src/internal/provider/RuntimeProvider.tsx
|
|
38
|
+
var import_react4 = __toESM(require("react"), 1);
|
|
39
|
+
var import_effect5 = require("effect");
|
|
40
|
+
var Logix5 = __toESM(require("@logixjs/core"), 1);
|
|
41
|
+
|
|
42
|
+
// src/internal/provider/ReactContext.ts
|
|
43
|
+
var import_react = require("react");
|
|
44
|
+
var RuntimeContext = (0, import_react.createContext)(null);
|
|
45
|
+
|
|
46
|
+
// src/internal/provider/config.ts
|
|
47
|
+
var import_effect = require("effect");
|
|
48
|
+
var ReactRuntimeConfigTag = class extends import_effect.Context.Tag("@logixjs/react/RuntimeConfig")() {
|
|
49
|
+
};
|
|
50
|
+
var DEFAULT_CONFIG = {
|
|
51
|
+
gcTime: 500,
|
|
52
|
+
initTimeoutMs: void 0,
|
|
53
|
+
lowPriorityDelayMs: 16,
|
|
54
|
+
lowPriorityMaxDelayMs: 50
|
|
55
|
+
};
|
|
56
|
+
var DEFAULT_CONFIG_SNAPSHOT = {
|
|
57
|
+
gcTime: DEFAULT_CONFIG.gcTime,
|
|
58
|
+
initTimeoutMs: DEFAULT_CONFIG.initTimeoutMs,
|
|
59
|
+
lowPriorityDelayMs: DEFAULT_CONFIG.lowPriorityDelayMs ?? 16,
|
|
60
|
+
lowPriorityMaxDelayMs: DEFAULT_CONFIG.lowPriorityMaxDelayMs ?? 50,
|
|
61
|
+
source: "default"
|
|
62
|
+
};
|
|
63
|
+
var ReactModuleConfigFromEnv = {
|
|
64
|
+
/**
|
|
65
|
+
* Default gcTime (ms) used as the idle keep-alive time for ModuleCache.
|
|
66
|
+
* - Applies when not explicitly specified in useModule(options.gcTime).
|
|
67
|
+
* - Default: 500ms (StrictMode jitter protection).
|
|
68
|
+
*/
|
|
69
|
+
gcTime: import_effect.Config.number("logix.react.gc_time").pipe(import_effect.Config.withDefault(DEFAULT_CONFIG.gcTime)),
|
|
70
|
+
/**
|
|
71
|
+
* Default init timeout (ms), only effective when suspend:true.
|
|
72
|
+
* - Uses Option<number> to represent "optional config": missing means init timeout is disabled.
|
|
73
|
+
* - Callers can map Option.none to undefined.
|
|
74
|
+
*/
|
|
75
|
+
initTimeoutMs: import_effect.Config.option(import_effect.Config.number("logix.react.init_timeout_ms")),
|
|
76
|
+
/**
|
|
77
|
+
* Delay (ms) for low-priority notification scheduling.
|
|
78
|
+
* - Roughly "defer to the next frame" cadence (default 16ms).
|
|
79
|
+
*/
|
|
80
|
+
lowPriorityDelayMs: import_effect.Config.number("logix.react.low_priority_delay_ms").pipe(
|
|
81
|
+
import_effect.Config.withDefault(DEFAULT_CONFIG.lowPriorityDelayMs ?? 16)
|
|
82
|
+
),
|
|
83
|
+
/**
|
|
84
|
+
* Maximum delay upper bound (ms) for low-priority notification scheduling.
|
|
85
|
+
* - Ensures eventual delivery, avoiding indefinite coalescing under extreme high-frequency scenarios.
|
|
86
|
+
* - Default 50ms.
|
|
87
|
+
*/
|
|
88
|
+
lowPriorityMaxDelayMs: import_effect.Config.number("logix.react.low_priority_max_delay_ms").pipe(
|
|
89
|
+
import_effect.Config.withDefault(DEFAULT_CONFIG.lowPriorityMaxDelayMs ?? 50)
|
|
90
|
+
)
|
|
91
|
+
};
|
|
92
|
+
var ReactModuleConfig = {
|
|
93
|
+
gcTime: import_effect.Effect.gen(function* () {
|
|
94
|
+
const override = yield* import_effect.Effect.serviceOption(ReactRuntimeConfigTag);
|
|
95
|
+
if (import_effect.Option.isSome(override)) {
|
|
96
|
+
return override.value.gcTime;
|
|
97
|
+
}
|
|
98
|
+
const value = yield* ReactModuleConfigFromEnv.gcTime;
|
|
99
|
+
return value;
|
|
100
|
+
}),
|
|
101
|
+
initTimeoutMs: import_effect.Effect.gen(function* () {
|
|
102
|
+
const override = yield* import_effect.Effect.serviceOption(ReactRuntimeConfigTag);
|
|
103
|
+
if (import_effect.Option.isSome(override)) {
|
|
104
|
+
const v = override.value.initTimeoutMs;
|
|
105
|
+
return v === void 0 ? import_effect.Option.none() : import_effect.Option.some(v);
|
|
106
|
+
}
|
|
107
|
+
const opt = yield* ReactModuleConfigFromEnv.initTimeoutMs;
|
|
108
|
+
return opt;
|
|
109
|
+
}),
|
|
110
|
+
lowPriorityDelayMs: import_effect.Effect.gen(function* () {
|
|
111
|
+
const override = yield* import_effect.Effect.serviceOption(ReactRuntimeConfigTag);
|
|
112
|
+
if (import_effect.Option.isSome(override)) {
|
|
113
|
+
return override.value.lowPriorityDelayMs ?? DEFAULT_CONFIG.lowPriorityDelayMs ?? 16;
|
|
114
|
+
}
|
|
115
|
+
const value = yield* ReactModuleConfigFromEnv.lowPriorityDelayMs;
|
|
116
|
+
return value;
|
|
117
|
+
}),
|
|
118
|
+
lowPriorityMaxDelayMs: import_effect.Effect.gen(function* () {
|
|
119
|
+
const override = yield* import_effect.Effect.serviceOption(ReactRuntimeConfigTag);
|
|
120
|
+
if (import_effect.Option.isSome(override)) {
|
|
121
|
+
return override.value.lowPriorityMaxDelayMs ?? DEFAULT_CONFIG.lowPriorityMaxDelayMs ?? 50;
|
|
122
|
+
}
|
|
123
|
+
const value = yield* ReactModuleConfigFromEnv.lowPriorityMaxDelayMs;
|
|
124
|
+
return value;
|
|
125
|
+
})
|
|
126
|
+
};
|
|
127
|
+
var ReactRuntimeConfigSnapshot = {
|
|
128
|
+
load: import_effect.Effect.gen(function* () {
|
|
129
|
+
const runtimeOverride = yield* import_effect.Effect.serviceOption(ReactRuntimeConfigTag);
|
|
130
|
+
if (import_effect.Option.isSome(runtimeOverride)) {
|
|
131
|
+
return {
|
|
132
|
+
gcTime: runtimeOverride.value.gcTime,
|
|
133
|
+
initTimeoutMs: runtimeOverride.value.initTimeoutMs,
|
|
134
|
+
lowPriorityDelayMs: runtimeOverride.value.lowPriorityDelayMs ?? DEFAULT_CONFIG.lowPriorityDelayMs ?? 16,
|
|
135
|
+
lowPriorityMaxDelayMs: runtimeOverride.value.lowPriorityMaxDelayMs ?? DEFAULT_CONFIG.lowPriorityMaxDelayMs ?? 50,
|
|
136
|
+
source: "runtime"
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const envGcTime = yield* ReactModuleConfigFromEnv.gcTime;
|
|
140
|
+
const envInitTimeoutOpt = yield* ReactModuleConfigFromEnv.initTimeoutMs;
|
|
141
|
+
const envInitTimeout = import_effect.Option.getOrUndefined(envInitTimeoutOpt);
|
|
142
|
+
const envLowPriorityDelayMs = yield* ReactModuleConfigFromEnv.lowPriorityDelayMs;
|
|
143
|
+
const envLowPriorityMaxDelayMs = yield* ReactModuleConfigFromEnv.lowPriorityMaxDelayMs;
|
|
144
|
+
const fromConfig = envGcTime !== DEFAULT_CONFIG.gcTime || import_effect.Option.isSome(envInitTimeoutOpt) || envLowPriorityDelayMs !== (DEFAULT_CONFIG.lowPriorityDelayMs ?? 16) || envLowPriorityMaxDelayMs !== (DEFAULT_CONFIG.lowPriorityMaxDelayMs ?? 50);
|
|
145
|
+
if (fromConfig) {
|
|
146
|
+
return {
|
|
147
|
+
gcTime: envGcTime,
|
|
148
|
+
initTimeoutMs: envInitTimeout,
|
|
149
|
+
lowPriorityDelayMs: envLowPriorityDelayMs,
|
|
150
|
+
lowPriorityMaxDelayMs: envLowPriorityMaxDelayMs,
|
|
151
|
+
source: "config"
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return DEFAULT_CONFIG_SNAPSHOT;
|
|
155
|
+
})
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// src/internal/provider/fallback.tsx
|
|
159
|
+
var import_react2 = require("react");
|
|
160
|
+
var Logix = __toESM(require("@logixjs/core"), 1);
|
|
161
|
+
|
|
162
|
+
// src/internal/provider/env.ts
|
|
163
|
+
var import_Env = require("@logixjs/core/Env");
|
|
164
|
+
|
|
165
|
+
// src/internal/provider/docs.ts
|
|
166
|
+
var LOGIX_DOCS_PREFIX_ENV = "LOGIX_DOCS_PREFIX";
|
|
167
|
+
var stripTrailingSlashes = (value) => value.replace(/\/+$/, "");
|
|
168
|
+
var ensureLeadingSlash = (value) => value.startsWith("/") ? value : `/${value}`;
|
|
169
|
+
var getProcessEnvString = (key) => {
|
|
170
|
+
try {
|
|
171
|
+
const env = globalThis?.process?.env;
|
|
172
|
+
const value = env?.[key];
|
|
173
|
+
return typeof value === "string" ? value : void 0;
|
|
174
|
+
} catch {
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
var getLocationOrigin = () => {
|
|
179
|
+
try {
|
|
180
|
+
const origin = globalThis?.location?.origin;
|
|
181
|
+
return typeof origin === "string" && origin.length > 0 ? origin : void 0;
|
|
182
|
+
} catch {
|
|
183
|
+
return void 0;
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
var getDocsRootPrefix = () => {
|
|
187
|
+
const raw = getProcessEnvString(LOGIX_DOCS_PREFIX_ENV);
|
|
188
|
+
const fromEnv = raw ? stripTrailingSlashes(raw.trim()) : void 0;
|
|
189
|
+
if (fromEnv && fromEnv.length > 0) {
|
|
190
|
+
if (/^https?:\/\//i.test(fromEnv)) {
|
|
191
|
+
return fromEnv;
|
|
192
|
+
}
|
|
193
|
+
const origin2 = getLocationOrigin();
|
|
194
|
+
if (origin2) {
|
|
195
|
+
return stripTrailingSlashes(`${origin2}${ensureLeadingSlash(fromEnv)}`);
|
|
196
|
+
}
|
|
197
|
+
return fromEnv;
|
|
198
|
+
}
|
|
199
|
+
const origin = getLocationOrigin();
|
|
200
|
+
return origin ? `${origin}/zh/docs` : void 0;
|
|
201
|
+
};
|
|
202
|
+
var resolveLogixDocsUrl = (docsPath) => {
|
|
203
|
+
const docsRoot = getDocsRootPrefix();
|
|
204
|
+
const path = ensureLeadingSlash(docsPath);
|
|
205
|
+
if (docsRoot) {
|
|
206
|
+
return `${stripTrailingSlashes(docsRoot)}${path}`;
|
|
207
|
+
}
|
|
208
|
+
return path;
|
|
209
|
+
};
|
|
210
|
+
var getFallbackWarningDocsUrl = () => resolveLogixDocsUrl("/guide/essentials/react-integration");
|
|
211
|
+
var getFallbackWarningDocsPrefixEnv = () => LOGIX_DOCS_PREFIX_ENV;
|
|
212
|
+
|
|
213
|
+
// src/internal/provider/fallback.tsx
|
|
214
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
215
|
+
var FALLBACK_WARNED_BY_RUNTIME = /* @__PURE__ */ new WeakMap();
|
|
216
|
+
var DEFAULT_FALLBACK_WARN_THRESHOLD_MS = 100;
|
|
217
|
+
var DEFAULT_FALLBACK_FLASH_HINT_MIN_MS = 16;
|
|
218
|
+
var DefaultRuntimeFallback = ({ phase, policyMode }) => {
|
|
219
|
+
const [elapsedMs, setElapsedMs] = (0, import_react2.useState)(0);
|
|
220
|
+
(0, import_react2.useEffect)(() => {
|
|
221
|
+
const start = performance.now();
|
|
222
|
+
const interval = setInterval(() => {
|
|
223
|
+
setElapsedMs(Math.round(performance.now() - start));
|
|
224
|
+
}, 100);
|
|
225
|
+
return () => {
|
|
226
|
+
clearInterval(interval);
|
|
227
|
+
};
|
|
228
|
+
}, []);
|
|
229
|
+
const message = phase === "provider.gating" ? "Logix \u8FD0\u884C\u65F6\u51C6\u5907\u4E2D\u2026" : "Logix \u6A21\u5757\u89E3\u6790\u4E2D\u2026";
|
|
230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
231
|
+
"div",
|
|
232
|
+
{
|
|
233
|
+
style: {
|
|
234
|
+
padding: 12,
|
|
235
|
+
fontSize: 13,
|
|
236
|
+
lineHeight: 1.4,
|
|
237
|
+
opacity: 0.85,
|
|
238
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
|
|
239
|
+
},
|
|
240
|
+
children: [
|
|
241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
242
|
+
message,
|
|
243
|
+
" ",
|
|
244
|
+
elapsedMs,
|
|
245
|
+
"ms"
|
|
246
|
+
] }),
|
|
247
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: 6, opacity: 0.8 }, children: [
|
|
248
|
+
"policy.mode=",
|
|
249
|
+
policyMode,
|
|
250
|
+
"\uFF08\u60F3\u201C\u65E0\u7B49\u5F85\u201D\u2192 sync\uFF1B\u60F3\u201C\u5C11\u95EA\u70C1\u201D\u2192 defer+preload\uFF09"
|
|
251
|
+
] })
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
);
|
|
255
|
+
};
|
|
256
|
+
var resolveRuntimeProviderFallback = (args) => {
|
|
257
|
+
if (args.fallback !== void 0) {
|
|
258
|
+
return args.fallback;
|
|
259
|
+
}
|
|
260
|
+
if (!(0, import_Env.isDevEnv)()) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultRuntimeFallback, { phase: args.phase, policyMode: args.policyMode });
|
|
264
|
+
};
|
|
265
|
+
var recordFallbackDuration = (args) => {
|
|
266
|
+
if (!(0, import_Env.isDevEnv)() && !Logix.Debug.isDevtoolsEnabled()) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
void args.runtime.runPromise(
|
|
270
|
+
Logix.Debug.record({
|
|
271
|
+
type: "trace:react.fallback.duration",
|
|
272
|
+
data: {
|
|
273
|
+
phase: args.phase,
|
|
274
|
+
policyMode: args.policyMode,
|
|
275
|
+
durationMs: Math.round(args.durationMs * 100) / 100,
|
|
276
|
+
blockers: args.blockers
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
).catch(() => {
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
var warnFallbackDuration = (args) => {
|
|
283
|
+
if (!(0, import_Env.isDevEnv)()) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const warnThresholdMs = DEFAULT_FALLBACK_WARN_THRESHOLD_MS;
|
|
287
|
+
const isVisibleLong = args.durationMs >= warnThresholdMs;
|
|
288
|
+
const isFlashHint = args.phase === "react.suspense" && args.policyMode !== "sync" && args.durationMs >= DEFAULT_FALLBACK_FLASH_HINT_MIN_MS && args.durationMs < warnThresholdMs;
|
|
289
|
+
if (!isVisibleLong && !isFlashHint) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const runtimeKey = args.runtime;
|
|
293
|
+
const warned = FALLBACK_WARNED_BY_RUNTIME.get(runtimeKey) ?? /* @__PURE__ */ new Set();
|
|
294
|
+
FALLBACK_WARNED_BY_RUNTIME.set(runtimeKey, warned);
|
|
295
|
+
const kind = isVisibleLong ? "visible" : "flash";
|
|
296
|
+
const dedupeKey = `${kind}::${args.phase}::${args.policyMode}::${args.blockers ?? "none"}`;
|
|
297
|
+
if (warned.has(dedupeKey)) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
warned.add(dedupeKey);
|
|
301
|
+
const docs = `Docs: ${getFallbackWarningDocsUrl()} (override via ${getFallbackWarningDocsPrefixEnv()})`;
|
|
302
|
+
const header = isVisibleLong ? "[Logix][React] Fallback visible" : "[Logix][React] Suspense fallback resolved quickly";
|
|
303
|
+
const hint = (() => {
|
|
304
|
+
if (isVisibleLong) {
|
|
305
|
+
if (args.phase === "provider.gating") {
|
|
306
|
+
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).";
|
|
307
|
+
}
|
|
308
|
+
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).';
|
|
309
|
+
}
|
|
310
|
+
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).';
|
|
311
|
+
})();
|
|
312
|
+
const example = (() => {
|
|
313
|
+
if (isFlashHint) {
|
|
314
|
+
return 'Example: <RuntimeProvider policy={{ mode: "sync" }} fallback={<Loading />}>\u2026</RuntimeProvider>';
|
|
315
|
+
}
|
|
316
|
+
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>';
|
|
317
|
+
})();
|
|
318
|
+
const log = isVisibleLong ? console.warn : console.info;
|
|
319
|
+
log(
|
|
320
|
+
header,
|
|
321
|
+
`(${Math.round(args.durationMs)}ms)`,
|
|
322
|
+
"\n",
|
|
323
|
+
`phase=${args.phase}`,
|
|
324
|
+
"\n",
|
|
325
|
+
`policy.mode=${args.policyMode}`,
|
|
326
|
+
args.blockers ? `
|
|
327
|
+
blockers=${args.blockers}` : "",
|
|
328
|
+
"\n",
|
|
329
|
+
hint,
|
|
330
|
+
"\n",
|
|
331
|
+
example,
|
|
332
|
+
"\n",
|
|
333
|
+
docs
|
|
334
|
+
);
|
|
335
|
+
};
|
|
336
|
+
var FallbackProbeEnabled = ({ runtime, phase, policyMode, blockers, children }) => {
|
|
337
|
+
(0, import_react2.useEffect)(() => {
|
|
338
|
+
const startedAt = performance.now();
|
|
339
|
+
return () => {
|
|
340
|
+
const durationMs = performance.now() - startedAt;
|
|
341
|
+
recordFallbackDuration({ runtime, phase, policyMode, durationMs, blockers });
|
|
342
|
+
warnFallbackDuration({ runtime, phase, policyMode, durationMs, blockers });
|
|
343
|
+
};
|
|
344
|
+
}, [runtime, phase, policyMode, blockers]);
|
|
345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
346
|
+
};
|
|
347
|
+
var FallbackProbeNoop = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
348
|
+
var FallbackProbe = (props) => {
|
|
349
|
+
const enabled = (0, import_Env.isDevEnv)() || Logix.Debug.isDevtoolsEnabled();
|
|
350
|
+
const Impl = enabled ? FallbackProbeEnabled : FallbackProbeNoop;
|
|
351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Impl, { ...props });
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// src/internal/provider/runtimeBindings.ts
|
|
355
|
+
var import_react3 = require("react");
|
|
356
|
+
var import_effect2 = require("effect");
|
|
357
|
+
var Logix2 = __toESM(require("@logixjs/core"), 1);
|
|
358
|
+
var toErrorString = (error) => error instanceof Error ? error.stack ?? error.message : String(error);
|
|
359
|
+
var debugScopeCloseFailure = (error) => {
|
|
360
|
+
if (!(0, import_Env.isDevEnv)()) return;
|
|
361
|
+
console.debug("[RuntimeProvider] Scope.close failed", toErrorString(error));
|
|
362
|
+
};
|
|
363
|
+
var useLayerBinding = (runtime, layer, enabled, onError) => {
|
|
364
|
+
const activeBindingRef = (0, import_react3.useRef)(null);
|
|
365
|
+
const [state, setState] = (0, import_react3.useState)(() => ({
|
|
366
|
+
binding: null,
|
|
367
|
+
isLoading: enabled && !!layer,
|
|
368
|
+
runtime,
|
|
369
|
+
layer,
|
|
370
|
+
enabled
|
|
371
|
+
}));
|
|
372
|
+
(0, import_react3.useEffect)(() => {
|
|
373
|
+
if (!enabled || !layer) {
|
|
374
|
+
const current2 = activeBindingRef.current;
|
|
375
|
+
if (current2) {
|
|
376
|
+
activeBindingRef.current = null;
|
|
377
|
+
void runtime.runPromise(import_effect2.Scope.close(current2.scope, import_effect2.Exit.void)).catch(debugScopeCloseFailure);
|
|
378
|
+
}
|
|
379
|
+
setState((prev) => {
|
|
380
|
+
if (prev.binding === null && prev.isLoading === false && prev.layer === void 0 && prev.enabled === enabled) {
|
|
381
|
+
return prev;
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
binding: null,
|
|
385
|
+
isLoading: false,
|
|
386
|
+
runtime: prev.runtime,
|
|
387
|
+
layer: void 0,
|
|
388
|
+
enabled
|
|
389
|
+
};
|
|
390
|
+
});
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const current = activeBindingRef.current;
|
|
394
|
+
if (current && current.runtime === runtime && current.layer === layer && current.enabled === enabled) {
|
|
395
|
+
setState({
|
|
396
|
+
binding: current,
|
|
397
|
+
isLoading: false,
|
|
398
|
+
runtime,
|
|
399
|
+
layer,
|
|
400
|
+
enabled
|
|
401
|
+
});
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const previousBinding = current ?? state.binding;
|
|
405
|
+
if ((0, import_Env.isDevEnv)() && previousBinding && previousBinding.layer !== layer && enabled && layer) {
|
|
406
|
+
console.warn(
|
|
407
|
+
"[RuntimeProvider] Rebuilding layer due to a new layer reference. Memoize the Layer in the caller to avoid repeated rebuilds and resource churn."
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
if (current) {
|
|
411
|
+
activeBindingRef.current = null;
|
|
412
|
+
void runtime.runPromise(import_effect2.Scope.close(current.scope, import_effect2.Exit.void)).catch(debugScopeCloseFailure);
|
|
413
|
+
}
|
|
414
|
+
let cancelled = false;
|
|
415
|
+
setState({
|
|
416
|
+
binding: null,
|
|
417
|
+
isLoading: true,
|
|
418
|
+
runtime,
|
|
419
|
+
layer,
|
|
420
|
+
enabled
|
|
421
|
+
});
|
|
422
|
+
const newScope = import_effect2.Effect.runSync(import_effect2.Scope.make());
|
|
423
|
+
const buildEffect = import_effect2.Effect.gen(function* () {
|
|
424
|
+
const context = yield* import_effect2.Layer.buildWithScope(layer, newScope);
|
|
425
|
+
const applyEnv = (effect) => import_effect2.Effect.mapInputContext(
|
|
426
|
+
import_effect2.Scope.extend(effect, newScope),
|
|
427
|
+
(parent) => import_effect2.Context.merge(parent, context)
|
|
428
|
+
);
|
|
429
|
+
const loggers = yield* applyEnv(import_effect2.FiberRef.get(import_effect2.FiberRef.currentLoggers));
|
|
430
|
+
const logLevel = yield* applyEnv(import_effect2.FiberRef.get(import_effect2.FiberRef.currentLogLevel));
|
|
431
|
+
const debugSinks = yield* applyEnv(
|
|
432
|
+
import_effect2.FiberRef.get(Logix2.Debug.internal.currentDebugSinks)
|
|
433
|
+
);
|
|
434
|
+
return { context, loggers, logLevel, debugSinks };
|
|
435
|
+
});
|
|
436
|
+
const assignBinding = (result) => {
|
|
437
|
+
if (cancelled) {
|
|
438
|
+
return runtime.runPromise(import_effect2.Scope.close(newScope, import_effect2.Exit.void)).catch(debugScopeCloseFailure);
|
|
439
|
+
}
|
|
440
|
+
const previous = activeBindingRef.current;
|
|
441
|
+
const newBinding = {
|
|
442
|
+
context: result.context,
|
|
443
|
+
loggers: result.loggers,
|
|
444
|
+
logLevel: result.logLevel,
|
|
445
|
+
debugSinks: result.debugSinks,
|
|
446
|
+
scope: newScope,
|
|
447
|
+
runtime,
|
|
448
|
+
layer,
|
|
449
|
+
enabled
|
|
450
|
+
};
|
|
451
|
+
activeBindingRef.current = newBinding;
|
|
452
|
+
setState({
|
|
453
|
+
binding: newBinding,
|
|
454
|
+
isLoading: false,
|
|
455
|
+
runtime,
|
|
456
|
+
layer,
|
|
457
|
+
enabled
|
|
458
|
+
});
|
|
459
|
+
if (previous) {
|
|
460
|
+
return runtime.runPromise(import_effect2.Scope.close(previous.scope, import_effect2.Exit.void)).catch(debugScopeCloseFailure);
|
|
461
|
+
}
|
|
462
|
+
return Promise.resolve();
|
|
463
|
+
};
|
|
464
|
+
let builtSync = false;
|
|
465
|
+
try {
|
|
466
|
+
const result = runtime.runSync(buildEffect);
|
|
467
|
+
builtSync = true;
|
|
468
|
+
void assignBinding(result);
|
|
469
|
+
} catch {
|
|
470
|
+
}
|
|
471
|
+
if (!builtSync) {
|
|
472
|
+
void runtime.runPromise(buildEffect).then(assignBinding).catch((error) => {
|
|
473
|
+
if (onError) {
|
|
474
|
+
const cause = import_effect2.Cause.die(error);
|
|
475
|
+
runtime.runFork(
|
|
476
|
+
onError(cause, { source: "provider", phase: "provider.layer.build" }).pipe(
|
|
477
|
+
import_effect2.Effect.catchAllCause(() => import_effect2.Effect.void)
|
|
478
|
+
)
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
void runtime.runPromise(import_effect2.Scope.close(newScope, import_effect2.Exit.void)).catch(debugScopeCloseFailure);
|
|
482
|
+
if (!cancelled) {
|
|
483
|
+
console.error("[RuntimeProvider] Failed to build layer", error);
|
|
484
|
+
setState({
|
|
485
|
+
binding: null,
|
|
486
|
+
isLoading: false,
|
|
487
|
+
runtime,
|
|
488
|
+
layer,
|
|
489
|
+
enabled
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
return () => {
|
|
495
|
+
cancelled = true;
|
|
496
|
+
const current2 = activeBindingRef.current;
|
|
497
|
+
if (current2) {
|
|
498
|
+
activeBindingRef.current = null;
|
|
499
|
+
void runtime.runPromise(import_effect2.Scope.close(current2.scope, import_effect2.Exit.void)).catch(debugScopeCloseFailure);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
void runtime.runPromise(import_effect2.Scope.close(newScope, import_effect2.Exit.void)).catch(debugScopeCloseFailure);
|
|
503
|
+
};
|
|
504
|
+
}, [runtime, layer, enabled, onError]);
|
|
505
|
+
const isCurrentBinding = state.binding !== null && state.runtime === runtime && state.layer === layer && state.enabled === enabled && enabled && !!layer;
|
|
506
|
+
return {
|
|
507
|
+
binding: isCurrentBinding ? state.binding : null,
|
|
508
|
+
isLoading: isCurrentBinding ? state.isLoading : enabled && !!layer
|
|
509
|
+
};
|
|
510
|
+
};
|
|
511
|
+
var createRuntimeAdapter = (runtime, contexts, scopes, loggerSets, logLevels, debugSinks) => {
|
|
512
|
+
if (contexts.length === 0 && scopes.length === 0 && loggerSets.length === 0 && logLevels.length === 0 && debugSinks.length === 0) {
|
|
513
|
+
return runtime;
|
|
514
|
+
}
|
|
515
|
+
const applyContexts = (effect) => (
|
|
516
|
+
// First inherit Provider scopes via scope.extend (preserving FiberRef/Logger changes),
|
|
517
|
+
// then merge Context via mapInputContext (inner overrides outer).
|
|
518
|
+
contexts.reduceRight(
|
|
519
|
+
(acc, ctx) => import_effect2.Effect.mapInputContext(
|
|
520
|
+
acc,
|
|
521
|
+
(parent) => import_effect2.Context.merge(parent, ctx)
|
|
522
|
+
),
|
|
523
|
+
scopes.reduceRight(
|
|
524
|
+
(acc, scope) => import_effect2.Scope.extend(acc, scope),
|
|
525
|
+
effect
|
|
526
|
+
)
|
|
527
|
+
)
|
|
528
|
+
);
|
|
529
|
+
const applyLoggers = (effect) => {
|
|
530
|
+
const last = loggerSets.length > 0 ? loggerSets[loggerSets.length - 1] : null;
|
|
531
|
+
const logLevel = logLevels.length > 0 ? logLevels[logLevels.length - 1] : null;
|
|
532
|
+
const sinks = debugSinks.length > 0 ? debugSinks[debugSinks.length - 1] : null;
|
|
533
|
+
let result = effect;
|
|
534
|
+
if (last) {
|
|
535
|
+
result = import_effect2.Effect.locally(import_effect2.FiberRef.currentLoggers, last)(result);
|
|
536
|
+
}
|
|
537
|
+
if (logLevel) {
|
|
538
|
+
result = import_effect2.Effect.locally(import_effect2.FiberRef.currentLogLevel, logLevel)(result);
|
|
539
|
+
}
|
|
540
|
+
if (sinks && sinks.length > 0) {
|
|
541
|
+
result = import_effect2.Effect.locally(
|
|
542
|
+
Logix2.Debug.internal.currentDebugSinks,
|
|
543
|
+
sinks
|
|
544
|
+
)(result);
|
|
545
|
+
}
|
|
546
|
+
return result;
|
|
547
|
+
};
|
|
548
|
+
const adapted = {
|
|
549
|
+
...runtime,
|
|
550
|
+
runFork: (effect, options) => runtime.runFork(applyLoggers(applyContexts(effect)), options),
|
|
551
|
+
runPromise: (effect, options) => runtime.runPromise(applyLoggers(applyContexts(effect)), options),
|
|
552
|
+
runPromiseExit: (effect, options) => runtime.runPromiseExit(applyLoggers(applyContexts(effect)), options),
|
|
553
|
+
runSync: (effect) => runtime.runSync(applyLoggers(applyContexts(effect))),
|
|
554
|
+
runSyncExit: (effect) => runtime.runSyncExit(applyLoggers(applyContexts(effect))),
|
|
555
|
+
runCallback: (effect, options) => runtime.runCallback(applyLoggers(applyContexts(effect)), options)
|
|
556
|
+
};
|
|
557
|
+
return adapted;
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
// src/internal/store/ModuleCache.ts
|
|
561
|
+
var Logix4 = __toESM(require("@logixjs/core"), 1);
|
|
562
|
+
var import_effect4 = require("effect");
|
|
563
|
+
|
|
564
|
+
// src/internal/store/perfWorkloads.ts
|
|
565
|
+
var Logix3 = __toESM(require("@logixjs/core"), 1);
|
|
566
|
+
var import_effect3 = require("effect");
|
|
567
|
+
var PerfCounterStateSchema = import_effect3.Schema.Struct({
|
|
568
|
+
value: import_effect3.Schema.Number
|
|
569
|
+
});
|
|
570
|
+
var PerfCounterActions = {
|
|
571
|
+
inc: import_effect3.Schema.Void
|
|
572
|
+
};
|
|
573
|
+
var PerfListScopeRowSchema = import_effect3.Schema.Struct({
|
|
574
|
+
id: import_effect3.Schema.String,
|
|
575
|
+
warehouseId: import_effect3.Schema.String
|
|
576
|
+
});
|
|
577
|
+
var PerfListScopeStateSchema = import_effect3.Schema.Struct({
|
|
578
|
+
items: import_effect3.Schema.Array(PerfListScopeRowSchema),
|
|
579
|
+
digest: import_effect3.Schema.String,
|
|
580
|
+
errors: import_effect3.Schema.Any
|
|
581
|
+
});
|
|
582
|
+
var GLOBAL_YIELD_BUDGET_MEMORY_KEY = "__LOGIX_REACT_YIELD_BUDGET_MEMORY__";
|
|
583
|
+
var getGlobalYieldBudgetMemory = () => {
|
|
584
|
+
const root = globalThis;
|
|
585
|
+
const existing = root[GLOBAL_YIELD_BUDGET_MEMORY_KEY];
|
|
586
|
+
if (existing && existing.byRuntime instanceof WeakMap) {
|
|
587
|
+
return existing;
|
|
588
|
+
}
|
|
589
|
+
const created = { byRuntime: /* @__PURE__ */ new WeakMap() };
|
|
590
|
+
root[GLOBAL_YIELD_BUDGET_MEMORY_KEY] = created;
|
|
591
|
+
return created;
|
|
592
|
+
};
|
|
593
|
+
var getStatsMapForRuntime = (runtime) => {
|
|
594
|
+
const global = getGlobalYieldBudgetMemory();
|
|
595
|
+
const cached = global.byRuntime.get(runtime);
|
|
596
|
+
if (cached) return cached;
|
|
597
|
+
const created = /* @__PURE__ */ new Map();
|
|
598
|
+
global.byRuntime.set(runtime, created);
|
|
599
|
+
return created;
|
|
600
|
+
};
|
|
601
|
+
var quantile = (sorted, q) => {
|
|
602
|
+
if (sorted.length === 0) return Number.NaN;
|
|
603
|
+
const clamped = Math.min(1, Math.max(0, q));
|
|
604
|
+
const idx = Math.floor(clamped * (sorted.length - 1));
|
|
605
|
+
return sorted[idx];
|
|
606
|
+
};
|
|
607
|
+
var p95 = (samplesMs) => {
|
|
608
|
+
if (samplesMs.length === 0) return Number.NaN;
|
|
609
|
+
const sorted = samplesMs.slice().sort((a, b) => a - b);
|
|
610
|
+
return quantile(sorted, 0.95);
|
|
611
|
+
};
|
|
612
|
+
var YieldBudgetMemory = {
|
|
613
|
+
shouldYield(args) {
|
|
614
|
+
const budgetMs = args.policy?.onlyWhenOverBudgetMs;
|
|
615
|
+
if (budgetMs === void 0) {
|
|
616
|
+
return { shouldYield: true, reason: "budgetDisabled", p95Ms: void 0 };
|
|
617
|
+
}
|
|
618
|
+
const byKey = getStatsMapForRuntime(args.runtime);
|
|
619
|
+
const stats = byKey.get(args.workloadKey) ?? { seen: false, samplesMs: [] };
|
|
620
|
+
if (!byKey.has(args.workloadKey)) {
|
|
621
|
+
byKey.set(args.workloadKey, stats);
|
|
622
|
+
}
|
|
623
|
+
if (!stats.seen) {
|
|
624
|
+
stats.seen = true;
|
|
625
|
+
return { shouldYield: true, reason: "firstRun", p95Ms: void 0 };
|
|
626
|
+
}
|
|
627
|
+
if (stats.samplesMs.length === 0) {
|
|
628
|
+
return { shouldYield: true, reason: "insufficientSamples", p95Ms: void 0 };
|
|
629
|
+
}
|
|
630
|
+
const p95Ms = p95(stats.samplesMs);
|
|
631
|
+
if (!Number.isFinite(p95Ms)) {
|
|
632
|
+
return { shouldYield: true, reason: "insufficientSamples", p95Ms: void 0 };
|
|
633
|
+
}
|
|
634
|
+
return p95Ms > budgetMs ? { shouldYield: true, reason: "overBudget", p95Ms } : { shouldYield: false, reason: "underBudget", p95Ms };
|
|
635
|
+
},
|
|
636
|
+
record(args) {
|
|
637
|
+
if (!Number.isFinite(args.durationMs) || args.durationMs < 0) return;
|
|
638
|
+
const byKey = getStatsMapForRuntime(args.runtime);
|
|
639
|
+
const stats = byKey.get(args.workloadKey) ?? { seen: true, samplesMs: [] };
|
|
640
|
+
if (!byKey.has(args.workloadKey)) {
|
|
641
|
+
byKey.set(args.workloadKey, stats);
|
|
642
|
+
}
|
|
643
|
+
stats.samplesMs.push(args.durationMs);
|
|
644
|
+
if (stats.samplesMs.length > 20) {
|
|
645
|
+
stats.samplesMs.shift();
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
// src/internal/store/ModuleCache.ts
|
|
651
|
+
var RUNTIME_CACHE = /* @__PURE__ */ new WeakMap();
|
|
652
|
+
var DEFAULT_GC_DELAY_MS = 500;
|
|
653
|
+
var ERROR_GC_DELAY_MS = 500;
|
|
654
|
+
var DEFAULT_RENDER_SYNC_BLOCKING_WARN_THRESHOLD_MS = 5;
|
|
655
|
+
var toErrorString2 = (error) => {
|
|
656
|
+
if (error instanceof Error) {
|
|
657
|
+
return error.stack ?? error.message;
|
|
658
|
+
}
|
|
659
|
+
return String(error);
|
|
660
|
+
};
|
|
661
|
+
var seenBestEffortFailures = /* @__PURE__ */ new Set();
|
|
662
|
+
var debugBestEffortFailure = (label, error) => {
|
|
663
|
+
if (!(0, import_Env.isDevEnv)()) return;
|
|
664
|
+
const message = toErrorString2(error);
|
|
665
|
+
if (message.includes("ManagedRuntime disposed")) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
const key = `${label}
|
|
669
|
+
${message}`;
|
|
670
|
+
if (seenBestEffortFailures.has(key)) return;
|
|
671
|
+
seenBestEffortFailures.add(key);
|
|
672
|
+
console.debug(label, message);
|
|
673
|
+
};
|
|
674
|
+
var causeToUnknown = (cause) => {
|
|
675
|
+
const failure = import_effect4.Option.getOrUndefined(import_effect4.Cause.failureOption(cause));
|
|
676
|
+
if (failure !== void 0) return failure;
|
|
677
|
+
const defect = import_effect4.Option.getOrUndefined(import_effect4.Cause.dieOption(cause));
|
|
678
|
+
if (defect !== void 0) return defect;
|
|
679
|
+
return cause;
|
|
680
|
+
};
|
|
681
|
+
var yieldEffect = (strategy) => {
|
|
682
|
+
switch (strategy) {
|
|
683
|
+
case "none":
|
|
684
|
+
return import_effect4.Effect.void;
|
|
685
|
+
case "microtask":
|
|
686
|
+
return import_effect4.Effect.yieldNow();
|
|
687
|
+
case "macrotask":
|
|
688
|
+
return import_effect4.Effect.promise(
|
|
689
|
+
() => new Promise((resolve) => {
|
|
690
|
+
setTimeout(resolve, 0);
|
|
691
|
+
})
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
var decideYieldStrategy = (runtime, workloadKey, policy) => {
|
|
696
|
+
const baseStrategy = policy?.strategy ?? "microtask";
|
|
697
|
+
if (baseStrategy === "none") {
|
|
698
|
+
return { strategy: "none", reason: "disabled" };
|
|
699
|
+
}
|
|
700
|
+
const budgetMs = policy?.onlyWhenOverBudgetMs;
|
|
701
|
+
if (budgetMs === void 0) {
|
|
702
|
+
return { strategy: baseStrategy };
|
|
703
|
+
}
|
|
704
|
+
const decision = YieldBudgetMemory.shouldYield({ runtime, workloadKey, policy });
|
|
705
|
+
return decision.shouldYield ? { strategy: baseStrategy, reason: decision.reason, p95Ms: decision.p95Ms } : { strategy: "none", reason: decision.reason, p95Ms: decision.p95Ms };
|
|
706
|
+
};
|
|
707
|
+
var warnedSyncBlockingKeys = /* @__PURE__ */ new Set();
|
|
708
|
+
var ModuleCache = class {
|
|
709
|
+
constructor(runtime, gcDelayMs = DEFAULT_GC_DELAY_MS) {
|
|
710
|
+
this.runtime = runtime;
|
|
711
|
+
this.gcDelayMs = gcDelayMs;
|
|
712
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
713
|
+
}
|
|
714
|
+
scheduleGC(key, entry) {
|
|
715
|
+
if (entry.gcTimeout) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
const delay = entry.gcTime;
|
|
719
|
+
if (!Number.isFinite(delay)) {
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
const timeoutMs = delay <= 0 ? 0 : delay;
|
|
723
|
+
entry.gcTimeout = setTimeout(() => {
|
|
724
|
+
const current = this.entries.get(key);
|
|
725
|
+
if (!current || current !== entry) {
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
current.gcTimeout = void 0;
|
|
729
|
+
if (current.refCount > 0 || current.preloadRefCount > 0) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (current.status === "pending") {
|
|
733
|
+
this.scheduleGC(key, current);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
void this.runtime.runPromise(import_effect4.Scope.close(current.scope, import_effect4.Exit.void)).catch((error) => {
|
|
737
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", error);
|
|
738
|
+
});
|
|
739
|
+
void this.runtime.runPromise(
|
|
740
|
+
Logix4.Debug.record({
|
|
741
|
+
type: "trace:react.module-instance",
|
|
742
|
+
moduleId: current.ownerId,
|
|
743
|
+
instanceId: current.value?.instanceId,
|
|
744
|
+
data: {
|
|
745
|
+
event: "gc",
|
|
746
|
+
key
|
|
747
|
+
}
|
|
748
|
+
})
|
|
749
|
+
).catch((error) => {
|
|
750
|
+
debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
|
|
751
|
+
});
|
|
752
|
+
this.entries.delete(key);
|
|
753
|
+
}, timeoutMs);
|
|
754
|
+
}
|
|
755
|
+
read(key, factory, gcTime, ownerId, options) {
|
|
756
|
+
const existing = this.entries.get(key);
|
|
757
|
+
if (existing) {
|
|
758
|
+
if ((0, import_Env.isDevEnv)() && existing.ownerId !== void 0 && ownerId !== void 0 && existing.ownerId !== ownerId) {
|
|
759
|
+
console.error(
|
|
760
|
+
"[ModuleCache.read] resource key ownership mismatch:",
|
|
761
|
+
`key="${key}" previously owned by "${existing.ownerId}",`,
|
|
762
|
+
`but now requested by "${ownerId}".`
|
|
763
|
+
);
|
|
764
|
+
throw new Error(
|
|
765
|
+
`[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.`
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
if (existing.status === "pending") {
|
|
769
|
+
throw existing.promise;
|
|
770
|
+
}
|
|
771
|
+
if (existing.status === "error") {
|
|
772
|
+
throw existing.error;
|
|
773
|
+
}
|
|
774
|
+
return existing.value;
|
|
775
|
+
}
|
|
776
|
+
const scope = import_effect4.Effect.runSync(import_effect4.Scope.make());
|
|
777
|
+
const workloadKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`;
|
|
778
|
+
const yieldDecision = decideYieldStrategy(this.runtime, workloadKey, options?.yield);
|
|
779
|
+
const entry = {
|
|
780
|
+
scope,
|
|
781
|
+
status: "pending",
|
|
782
|
+
// Placeholder; will be replaced immediately with the real Promise.
|
|
783
|
+
promise: Promise.resolve(null),
|
|
784
|
+
refCount: 0,
|
|
785
|
+
preloadRefCount: 0,
|
|
786
|
+
gcTime: gcTime ?? this.gcDelayMs,
|
|
787
|
+
ownerId,
|
|
788
|
+
createdBy: "read",
|
|
789
|
+
workloadKey,
|
|
790
|
+
yieldStrategy: yieldDecision.strategy
|
|
791
|
+
};
|
|
792
|
+
this.scheduleGC(key, entry);
|
|
793
|
+
const startedAt = performance.now();
|
|
794
|
+
const buildEffect = yieldEffect(yieldDecision.strategy).pipe(import_effect4.Effect.zipRight(factory(scope)));
|
|
795
|
+
const fiber = this.runtime.runFork(buildEffect);
|
|
796
|
+
entry.fiber = fiber;
|
|
797
|
+
const promise = this.runtime.runPromise(import_effect4.Fiber.await(fiber)).then((exit) => {
|
|
798
|
+
if (import_effect4.Exit.isSuccess(exit)) return exit.value;
|
|
799
|
+
throw causeToUnknown(exit.cause);
|
|
800
|
+
});
|
|
801
|
+
promise.then((value) => {
|
|
802
|
+
entry.status = "success";
|
|
803
|
+
entry.value = value;
|
|
804
|
+
const durationMs = performance.now() - startedAt;
|
|
805
|
+
YieldBudgetMemory.record({ runtime: this.runtime, workloadKey, durationMs });
|
|
806
|
+
if ((0, import_Env.isDevEnv)() || Logix4.Debug.isDevtoolsEnabled()) {
|
|
807
|
+
void this.runtime.runPromise(
|
|
808
|
+
Logix4.Debug.record({
|
|
809
|
+
type: "trace:react.module.init",
|
|
810
|
+
moduleId: ownerId,
|
|
811
|
+
instanceId: value.instanceId,
|
|
812
|
+
data: {
|
|
813
|
+
mode: "suspend",
|
|
814
|
+
key,
|
|
815
|
+
durationMs: Math.round(durationMs * 100) / 100,
|
|
816
|
+
yieldStrategy: yieldDecision.strategy,
|
|
817
|
+
yieldReason: yieldDecision.reason,
|
|
818
|
+
yieldP95Ms: yieldDecision.p95Ms
|
|
819
|
+
}
|
|
820
|
+
})
|
|
821
|
+
).catch((error) => {
|
|
822
|
+
debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
|
|
823
|
+
});
|
|
824
|
+
void this.runtime.runPromise(
|
|
825
|
+
Logix4.Debug.record({
|
|
826
|
+
type: "trace:react.module-instance",
|
|
827
|
+
moduleId: ownerId,
|
|
828
|
+
instanceId: value.instanceId,
|
|
829
|
+
data: {
|
|
830
|
+
event: "attach",
|
|
831
|
+
key,
|
|
832
|
+
mode: "suspend",
|
|
833
|
+
gcTime: entry.gcTime
|
|
834
|
+
}
|
|
835
|
+
})
|
|
836
|
+
).catch((error) => {
|
|
837
|
+
debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
return value;
|
|
841
|
+
}).catch((error) => {
|
|
842
|
+
entry.status = "error";
|
|
843
|
+
entry.error = error;
|
|
844
|
+
entry.gcTime = ERROR_GC_DELAY_MS;
|
|
845
|
+
if (entry.gcTimeout) {
|
|
846
|
+
clearTimeout(entry.gcTimeout);
|
|
847
|
+
entry.gcTimeout = void 0;
|
|
848
|
+
}
|
|
849
|
+
this.scheduleGC(key, entry);
|
|
850
|
+
YieldBudgetMemory.record({
|
|
851
|
+
runtime: this.runtime,
|
|
852
|
+
workloadKey,
|
|
853
|
+
durationMs: performance.now() - startedAt
|
|
854
|
+
});
|
|
855
|
+
void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
|
|
856
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
|
|
857
|
+
});
|
|
858
|
+
throw error;
|
|
859
|
+
});
|
|
860
|
+
this.entries.set(key, entry);
|
|
861
|
+
entry.promise = promise;
|
|
862
|
+
throw promise;
|
|
863
|
+
}
|
|
864
|
+
readSync(key, factory, gcTime, ownerId, options) {
|
|
865
|
+
const existing = this.entries.get(key);
|
|
866
|
+
if (existing) {
|
|
867
|
+
if ((0, import_Env.isDevEnv)() && existing.ownerId !== void 0 && ownerId !== void 0 && existing.ownerId !== ownerId) {
|
|
868
|
+
console.error(
|
|
869
|
+
"[ModuleCache.readSync] resource key ownership mismatch:",
|
|
870
|
+
`key="${key}" previously owned by "${existing.ownerId}",`,
|
|
871
|
+
`but now requested by "${ownerId}".`
|
|
872
|
+
);
|
|
873
|
+
throw new Error(
|
|
874
|
+
`[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.`
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
if (existing.status === "error") {
|
|
878
|
+
throw existing.error;
|
|
879
|
+
}
|
|
880
|
+
if (existing.status === "pending") {
|
|
881
|
+
throw new Error(
|
|
882
|
+
`[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.`
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
return existing.value;
|
|
886
|
+
}
|
|
887
|
+
const scope = this.runtime.runSync(import_effect4.Scope.make());
|
|
888
|
+
const startedAt = performance.now();
|
|
889
|
+
try {
|
|
890
|
+
const value = this.runtime.runSync(factory(scope));
|
|
891
|
+
const durationMs = performance.now() - startedAt;
|
|
892
|
+
const entry = {
|
|
893
|
+
scope,
|
|
894
|
+
status: "success",
|
|
895
|
+
promise: Promise.resolve(value),
|
|
896
|
+
value,
|
|
897
|
+
refCount: 0,
|
|
898
|
+
preloadRefCount: 0,
|
|
899
|
+
gcTime: gcTime ?? this.gcDelayMs,
|
|
900
|
+
ownerId,
|
|
901
|
+
createdBy: "read",
|
|
902
|
+
workloadKey: `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`,
|
|
903
|
+
yieldStrategy: "none"
|
|
904
|
+
};
|
|
905
|
+
this.scheduleGC(key, entry);
|
|
906
|
+
this.entries.set(key, entry);
|
|
907
|
+
if ((0, import_Env.isDevEnv)()) {
|
|
908
|
+
const threshold = options?.warnSyncBlockingThresholdMs ?? DEFAULT_RENDER_SYNC_BLOCKING_WARN_THRESHOLD_MS;
|
|
909
|
+
if (threshold > 0 && durationMs > threshold) {
|
|
910
|
+
const dedupeKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}::${key}`;
|
|
911
|
+
if (!warnedSyncBlockingKeys.has(dedupeKey)) {
|
|
912
|
+
warnedSyncBlockingKeys.add(dedupeKey);
|
|
913
|
+
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';
|
|
914
|
+
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>';
|
|
915
|
+
const docs = "Docs: apps/docs/content/docs/guide/essentials/react-integration.md";
|
|
916
|
+
console.warn(
|
|
917
|
+
"[Logix][React] Render-phase sync blocking detected",
|
|
918
|
+
`(${Math.round(durationMs * 100) / 100}ms > ${threshold}ms)`,
|
|
919
|
+
"\n",
|
|
920
|
+
`entrypoint=${options?.entrypoint ?? "unknown"}`,
|
|
921
|
+
"\n",
|
|
922
|
+
`ownerId=${ownerId ?? "unknown"}`,
|
|
923
|
+
"\n",
|
|
924
|
+
`key=${key}`,
|
|
925
|
+
"\n",
|
|
926
|
+
hint,
|
|
927
|
+
"\n",
|
|
928
|
+
example,
|
|
929
|
+
"\n",
|
|
930
|
+
docs
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
if ((0, import_Env.isDevEnv)() || Logix4.Debug.isDevtoolsEnabled()) {
|
|
936
|
+
void this.runtime.runPromise(
|
|
937
|
+
Logix4.Debug.record({
|
|
938
|
+
type: "trace:react.module.init",
|
|
939
|
+
moduleId: ownerId,
|
|
940
|
+
instanceId: value.instanceId,
|
|
941
|
+
data: {
|
|
942
|
+
mode: "sync",
|
|
943
|
+
key,
|
|
944
|
+
durationMs: Math.round(durationMs * 100) / 100,
|
|
945
|
+
yieldStrategy: "none"
|
|
946
|
+
}
|
|
947
|
+
})
|
|
948
|
+
).catch((error) => {
|
|
949
|
+
debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
|
|
950
|
+
});
|
|
951
|
+
void this.runtime.runPromise(
|
|
952
|
+
Logix4.Debug.record({
|
|
953
|
+
type: "trace:react.module-instance",
|
|
954
|
+
moduleId: ownerId,
|
|
955
|
+
instanceId: value.instanceId,
|
|
956
|
+
data: {
|
|
957
|
+
event: "attach",
|
|
958
|
+
key,
|
|
959
|
+
mode: "sync",
|
|
960
|
+
gcTime: entry.gcTime
|
|
961
|
+
}
|
|
962
|
+
})
|
|
963
|
+
).catch((error) => {
|
|
964
|
+
debugBestEffortFailure("[ModuleCache] Debug.record failed", error);
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
return value;
|
|
968
|
+
} catch (error) {
|
|
969
|
+
void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
|
|
970
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
|
|
971
|
+
});
|
|
972
|
+
const entry = {
|
|
973
|
+
scope,
|
|
974
|
+
status: "error",
|
|
975
|
+
promise: Promise.reject(error),
|
|
976
|
+
error,
|
|
977
|
+
refCount: 0,
|
|
978
|
+
preloadRefCount: 0,
|
|
979
|
+
gcTime: ERROR_GC_DELAY_MS,
|
|
980
|
+
ownerId,
|
|
981
|
+
createdBy: "read",
|
|
982
|
+
workloadKey: `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`,
|
|
983
|
+
yieldStrategy: "none"
|
|
984
|
+
};
|
|
985
|
+
this.scheduleGC(key, entry);
|
|
986
|
+
this.entries.set(key, entry);
|
|
987
|
+
throw error;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
preload(key, factory, options) {
|
|
991
|
+
const existing = this.entries.get(key);
|
|
992
|
+
if (existing) {
|
|
993
|
+
if (existing.status === "success") {
|
|
994
|
+
existing.preloadRefCount += 1;
|
|
995
|
+
return {
|
|
996
|
+
promise: Promise.resolve(existing.value),
|
|
997
|
+
cancel: () => {
|
|
998
|
+
this.cancelPreload(key, existing);
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
if (existing.status === "error") {
|
|
1003
|
+
return { promise: Promise.reject(existing.error), cancel: () => {
|
|
1004
|
+
} };
|
|
1005
|
+
}
|
|
1006
|
+
existing.preloadRefCount += 1;
|
|
1007
|
+
return {
|
|
1008
|
+
promise: existing.promise,
|
|
1009
|
+
cancel: () => {
|
|
1010
|
+
this.cancelPreload(key, existing);
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
const scope = import_effect4.Effect.runSync(import_effect4.Scope.make());
|
|
1015
|
+
const ownerId = options?.ownerId;
|
|
1016
|
+
const gcTime = options?.gcTime ?? this.gcDelayMs;
|
|
1017
|
+
const workloadKey = `${options?.entrypoint ?? "unknown"}::${ownerId ?? "unknown"}`;
|
|
1018
|
+
const yieldDecision = decideYieldStrategy(this.runtime, workloadKey, options?.yield);
|
|
1019
|
+
const entry = {
|
|
1020
|
+
scope,
|
|
1021
|
+
status: "pending",
|
|
1022
|
+
promise: Promise.resolve(null),
|
|
1023
|
+
refCount: 0,
|
|
1024
|
+
preloadRefCount: 1,
|
|
1025
|
+
gcTime,
|
|
1026
|
+
ownerId,
|
|
1027
|
+
createdBy: "preload",
|
|
1028
|
+
workloadKey,
|
|
1029
|
+
yieldStrategy: yieldDecision.strategy
|
|
1030
|
+
};
|
|
1031
|
+
this.scheduleGC(key, entry);
|
|
1032
|
+
this.entries.set(key, entry);
|
|
1033
|
+
const startedAt = performance.now();
|
|
1034
|
+
const buildEffect = yieldEffect(yieldDecision.strategy).pipe(import_effect4.Effect.zipRight(factory(scope)));
|
|
1035
|
+
const fiber = this.runtime.runFork(buildEffect);
|
|
1036
|
+
entry.fiber = fiber;
|
|
1037
|
+
const promise = this.runtime.runPromise(import_effect4.Fiber.await(fiber)).then((exit) => {
|
|
1038
|
+
if (import_effect4.Exit.isSuccess(exit)) return exit.value;
|
|
1039
|
+
throw causeToUnknown(exit.cause);
|
|
1040
|
+
});
|
|
1041
|
+
entry.promise = promise;
|
|
1042
|
+
void promise.then((value) => {
|
|
1043
|
+
entry.status = "success";
|
|
1044
|
+
entry.value = value;
|
|
1045
|
+
YieldBudgetMemory.record({
|
|
1046
|
+
runtime: this.runtime,
|
|
1047
|
+
workloadKey,
|
|
1048
|
+
durationMs: performance.now() - startedAt
|
|
1049
|
+
});
|
|
1050
|
+
}).catch((error) => {
|
|
1051
|
+
entry.status = "error";
|
|
1052
|
+
entry.error = error;
|
|
1053
|
+
entry.gcTime = ERROR_GC_DELAY_MS;
|
|
1054
|
+
if (entry.gcTimeout) {
|
|
1055
|
+
clearTimeout(entry.gcTimeout);
|
|
1056
|
+
entry.gcTimeout = void 0;
|
|
1057
|
+
}
|
|
1058
|
+
this.scheduleGC(key, entry);
|
|
1059
|
+
YieldBudgetMemory.record({
|
|
1060
|
+
runtime: this.runtime,
|
|
1061
|
+
workloadKey,
|
|
1062
|
+
durationMs: performance.now() - startedAt
|
|
1063
|
+
});
|
|
1064
|
+
void this.runtime.runPromise(import_effect4.Scope.close(scope, import_effect4.Exit.fail(error))).catch((closeError) => {
|
|
1065
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
|
|
1066
|
+
});
|
|
1067
|
+
});
|
|
1068
|
+
return {
|
|
1069
|
+
promise,
|
|
1070
|
+
cancel: () => {
|
|
1071
|
+
this.cancelPreload(key, entry);
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
cancelPreload(key, entry) {
|
|
1076
|
+
const current = this.entries.get(key);
|
|
1077
|
+
if (!current || current !== entry) {
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
entry.preloadRefCount = Math.max(0, entry.preloadRefCount - 1);
|
|
1081
|
+
if (entry.preloadRefCount > 0) {
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
if (entry.refCount > 0) {
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
if (entry.status === "pending") {
|
|
1088
|
+
if (entry.createdBy !== "preload") {
|
|
1089
|
+
this.scheduleGC(key, entry);
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
const running = entry.fiber;
|
|
1093
|
+
entry.fiber = void 0;
|
|
1094
|
+
this.entries.delete(key);
|
|
1095
|
+
if (running) {
|
|
1096
|
+
this.runtime.runFork(import_effect4.Fiber.interrupt(running));
|
|
1097
|
+
}
|
|
1098
|
+
void this.runtime.runPromise(import_effect4.Scope.close(entry.scope, import_effect4.Exit.void)).catch((closeError) => {
|
|
1099
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", closeError);
|
|
1100
|
+
});
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
if (entry.gcTimeout) {
|
|
1104
|
+
clearTimeout(entry.gcTimeout);
|
|
1105
|
+
entry.gcTimeout = void 0;
|
|
1106
|
+
}
|
|
1107
|
+
this.scheduleGC(key, entry);
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Declares ownership of a resource after component commit.
|
|
1111
|
+
* The returned function releases the reference during cleanup.
|
|
1112
|
+
*/
|
|
1113
|
+
retain(key) {
|
|
1114
|
+
const entry = this.entries.get(key);
|
|
1115
|
+
if (!entry) {
|
|
1116
|
+
return () => {
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
entry.refCount += 1;
|
|
1120
|
+
if (entry.gcTimeout) {
|
|
1121
|
+
clearTimeout(entry.gcTimeout);
|
|
1122
|
+
entry.gcTimeout = void 0;
|
|
1123
|
+
}
|
|
1124
|
+
return () => {
|
|
1125
|
+
this.release(key);
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
release(key) {
|
|
1129
|
+
const entry = this.entries.get(key);
|
|
1130
|
+
if (!entry) {
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
entry.refCount -= 1;
|
|
1134
|
+
if (entry.refCount > 0) {
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
this.scheduleGC(key, entry);
|
|
1138
|
+
}
|
|
1139
|
+
dispose() {
|
|
1140
|
+
for (const [key, entry] of this.entries) {
|
|
1141
|
+
if (entry.gcTimeout) {
|
|
1142
|
+
clearTimeout(entry.gcTimeout);
|
|
1143
|
+
}
|
|
1144
|
+
void this.runtime.runPromise(import_effect4.Scope.close(entry.scope, import_effect4.Exit.void)).catch((error) => {
|
|
1145
|
+
debugBestEffortFailure("[ModuleCache] Scope.close failed", error);
|
|
1146
|
+
});
|
|
1147
|
+
this.entries.delete(key);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
};
|
|
1151
|
+
var getModuleCache = (runtime, config, version) => {
|
|
1152
|
+
const cached = RUNTIME_CACHE.get(runtime);
|
|
1153
|
+
if (cached && cached.version === version) {
|
|
1154
|
+
return cached.cache;
|
|
1155
|
+
}
|
|
1156
|
+
if (cached) {
|
|
1157
|
+
cached.cache.dispose();
|
|
1158
|
+
}
|
|
1159
|
+
const cache = new ModuleCache(runtime, config.gcTime);
|
|
1160
|
+
RUNTIME_CACHE.set(runtime, { version, cache });
|
|
1161
|
+
return cache;
|
|
1162
|
+
};
|
|
1163
|
+
|
|
1164
|
+
// src/internal/provider/policy.ts
|
|
1165
|
+
var DEFAULT_PRELOAD_CONCURRENCY = 5;
|
|
1166
|
+
var DEFAULT_SYNC_BUDGET_MS = 5;
|
|
1167
|
+
var DEFAULT_YIELD_STRATEGY = "microtask";
|
|
1168
|
+
var isModuleImpl = (handle) => Boolean(handle) && typeof handle === "object" && handle._tag === "ModuleImpl";
|
|
1169
|
+
var isModuleTag = (handle) => {
|
|
1170
|
+
if (!handle || typeof handle !== "object" && typeof handle !== "function") {
|
|
1171
|
+
return false;
|
|
1172
|
+
}
|
|
1173
|
+
const candidate = handle;
|
|
1174
|
+
return candidate._kind === "ModuleTag";
|
|
1175
|
+
};
|
|
1176
|
+
var getPreloadKeyForModuleId = (moduleId) => `preload:impl:${moduleId}`;
|
|
1177
|
+
var getPreloadKeyForTagId = (tagId) => `preload:tag:${tagId}`;
|
|
1178
|
+
var normalizeYieldPolicy = (policy) => ({
|
|
1179
|
+
strategy: policy?.strategy ?? DEFAULT_YIELD_STRATEGY,
|
|
1180
|
+
onlyWhenOverBudgetMs: policy?.onlyWhenOverBudgetMs
|
|
1181
|
+
});
|
|
1182
|
+
var normalizePreload = (preload) => {
|
|
1183
|
+
if (!preload) return null;
|
|
1184
|
+
const policy = Array.isArray(preload) ? { handles: preload } : preload;
|
|
1185
|
+
const handles = [];
|
|
1186
|
+
for (const handle of policy.handles ?? []) {
|
|
1187
|
+
if (isModuleImpl(handle) || isModuleTag(handle)) {
|
|
1188
|
+
handles.push(handle);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
return {
|
|
1192
|
+
handles,
|
|
1193
|
+
concurrency: Math.max(1, policy.concurrency ?? DEFAULT_PRELOAD_CONCURRENCY),
|
|
1194
|
+
yield: normalizeYieldPolicy(policy.yield)
|
|
1195
|
+
};
|
|
1196
|
+
};
|
|
1197
|
+
var resolveRuntimeProviderPolicy = (args) => {
|
|
1198
|
+
const inheritedMode = args.parentPolicy?.mode;
|
|
1199
|
+
const mode = args.policy?.mode ?? (inheritedMode !== void 0 ? inheritedMode : "suspend");
|
|
1200
|
+
const moduleResolveMode = mode === "sync" ? "sync" : "suspend";
|
|
1201
|
+
const preload = mode === "defer" ? normalizePreload(args.policy?.preload) : null;
|
|
1202
|
+
const keysByModuleId = /* @__PURE__ */ new Map();
|
|
1203
|
+
const keysByTagId = /* @__PURE__ */ new Map();
|
|
1204
|
+
if (preload) {
|
|
1205
|
+
for (const handle of preload.handles) {
|
|
1206
|
+
if (isModuleImpl(handle)) {
|
|
1207
|
+
const moduleId = handle.module.id ?? "ModuleImpl";
|
|
1208
|
+
keysByModuleId.set(moduleId, getPreloadKeyForModuleId(moduleId));
|
|
1209
|
+
} else if (isModuleTag(handle)) {
|
|
1210
|
+
const tagId = handle.id ?? "ModuleTag";
|
|
1211
|
+
keysByTagId.set(tagId, getPreloadKeyForTagId(tagId));
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
return {
|
|
1216
|
+
mode,
|
|
1217
|
+
moduleImplMode: moduleResolveMode,
|
|
1218
|
+
moduleTagMode: moduleResolveMode,
|
|
1219
|
+
syncBudgetMs: Math.max(0, args.policy?.syncBudgetMs ?? args.parentPolicy?.syncBudgetMs ?? DEFAULT_SYNC_BUDGET_MS),
|
|
1220
|
+
yield: normalizeYieldPolicy(args.policy?.yield ?? args.parentPolicy?.yield),
|
|
1221
|
+
preload: preload ? {
|
|
1222
|
+
...preload,
|
|
1223
|
+
keysByModuleId,
|
|
1224
|
+
keysByTagId
|
|
1225
|
+
} : null
|
|
1226
|
+
};
|
|
1227
|
+
};
|
|
1228
|
+
|
|
1229
|
+
// src/internal/provider/RuntimeProvider.tsx
|
|
1230
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1231
|
+
var SYNC_CONFIG_OVER_BUDGET_BY_RUNTIME = /* @__PURE__ */ new WeakMap();
|
|
1232
|
+
var RuntimeProvider = ({
|
|
1233
|
+
layer,
|
|
1234
|
+
runtime,
|
|
1235
|
+
children,
|
|
1236
|
+
fallback,
|
|
1237
|
+
policy,
|
|
1238
|
+
onError
|
|
1239
|
+
}) => {
|
|
1240
|
+
const parent = (0, import_react4.useContext)(RuntimeContext);
|
|
1241
|
+
const baseRuntime = useRuntimeResolution(runtime, parent);
|
|
1242
|
+
const resolvedPolicy = (0, import_react4.useMemo)(
|
|
1243
|
+
() => resolveRuntimeProviderPolicy({
|
|
1244
|
+
policy,
|
|
1245
|
+
parentPolicy: parent?.policy ?? null
|
|
1246
|
+
}),
|
|
1247
|
+
[policy, parent?.policy]
|
|
1248
|
+
);
|
|
1249
|
+
const onErrorRef = import_react4.default.useRef(onError);
|
|
1250
|
+
onErrorRef.current = onError;
|
|
1251
|
+
const { binding: layerBinding } = useLayerBinding(baseRuntime, layer, Boolean(layer), onErrorRef.current);
|
|
1252
|
+
const onErrorSink = (0, import_react4.useMemo)(() => {
|
|
1253
|
+
if (!onError) return null;
|
|
1254
|
+
const sink = {
|
|
1255
|
+
record: (event) => {
|
|
1256
|
+
const handler = onErrorRef.current;
|
|
1257
|
+
if (!handler) {
|
|
1258
|
+
return import_effect5.Effect.void;
|
|
1259
|
+
}
|
|
1260
|
+
if (event.type === "lifecycle:error") {
|
|
1261
|
+
return handler(event.cause, {
|
|
1262
|
+
source: "provider",
|
|
1263
|
+
phase: "debug.lifecycle_error",
|
|
1264
|
+
moduleId: event.moduleId,
|
|
1265
|
+
instanceId: event.instanceId,
|
|
1266
|
+
runtimeLabel: event.runtimeLabel
|
|
1267
|
+
}).pipe(import_effect5.Effect.catchAllCause(() => import_effect5.Effect.void));
|
|
1268
|
+
}
|
|
1269
|
+
if (event.type === "diagnostic" && event.severity === "error") {
|
|
1270
|
+
return handler(
|
|
1271
|
+
import_effect5.Cause.fail({
|
|
1272
|
+
code: event.code,
|
|
1273
|
+
message: event.message,
|
|
1274
|
+
hint: event.hint
|
|
1275
|
+
}),
|
|
1276
|
+
{
|
|
1277
|
+
source: "provider",
|
|
1278
|
+
phase: "debug.diagnostic_error",
|
|
1279
|
+
code: event.code,
|
|
1280
|
+
message: event.message,
|
|
1281
|
+
hint: event.hint,
|
|
1282
|
+
moduleId: event.moduleId,
|
|
1283
|
+
instanceId: event.instanceId,
|
|
1284
|
+
runtimeLabel: event.runtimeLabel
|
|
1285
|
+
}
|
|
1286
|
+
).pipe(import_effect5.Effect.catchAllCause(() => import_effect5.Effect.void));
|
|
1287
|
+
}
|
|
1288
|
+
return import_effect5.Effect.void;
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
1291
|
+
return sink;
|
|
1292
|
+
}, [Boolean(onError)]);
|
|
1293
|
+
const inheritedDebugSinks = (0, import_react4.useMemo)(() => {
|
|
1294
|
+
if (!onErrorSink) {
|
|
1295
|
+
return [];
|
|
1296
|
+
}
|
|
1297
|
+
if (layerBinding) {
|
|
1298
|
+
return layerBinding.debugSinks;
|
|
1299
|
+
}
|
|
1300
|
+
try {
|
|
1301
|
+
return baseRuntime.runSync(
|
|
1302
|
+
import_effect5.FiberRef.get(Logix5.Debug.internal.currentDebugSinks)
|
|
1303
|
+
);
|
|
1304
|
+
} catch {
|
|
1305
|
+
return [];
|
|
1306
|
+
}
|
|
1307
|
+
}, [baseRuntime, layerBinding, onErrorSink]);
|
|
1308
|
+
const runtimeWithBindings = (0, import_react4.useMemo)(
|
|
1309
|
+
() => layerBinding || onErrorSink ? createRuntimeAdapter(
|
|
1310
|
+
baseRuntime,
|
|
1311
|
+
layerBinding ? [layerBinding.context] : [],
|
|
1312
|
+
layerBinding ? [layerBinding.scope] : [],
|
|
1313
|
+
layerBinding ? [layerBinding.loggers] : [],
|
|
1314
|
+
layerBinding ? [layerBinding.logLevel] : [],
|
|
1315
|
+
[
|
|
1316
|
+
onErrorSink ? [onErrorSink, ...inheritedDebugSinks] : layerBinding ? layerBinding.debugSinks : []
|
|
1317
|
+
]
|
|
1318
|
+
) : baseRuntime,
|
|
1319
|
+
[baseRuntime, inheritedDebugSinks, layerBinding, onErrorSink]
|
|
1320
|
+
);
|
|
1321
|
+
const didReportSyncConfigSnapshotRef = import_react4.default.useRef(false);
|
|
1322
|
+
const [configState, setConfigState] = (0, import_react4.useState)(() => {
|
|
1323
|
+
const budgetMs = resolvedPolicy.syncBudgetMs;
|
|
1324
|
+
if (budgetMs <= 0) {
|
|
1325
|
+
return { snapshot: DEFAULT_CONFIG_SNAPSHOT, version: 1, loaded: false, loadMode: "none" };
|
|
1326
|
+
}
|
|
1327
|
+
if (SYNC_CONFIG_OVER_BUDGET_BY_RUNTIME.has(baseRuntime)) {
|
|
1328
|
+
return { snapshot: DEFAULT_CONFIG_SNAPSHOT, version: 1, loaded: false, loadMode: "none" };
|
|
1329
|
+
}
|
|
1330
|
+
const startedAt = performance.now();
|
|
1331
|
+
try {
|
|
1332
|
+
const snapshot = runtimeWithBindings.runSync(
|
|
1333
|
+
ReactRuntimeConfigSnapshot.load
|
|
1334
|
+
);
|
|
1335
|
+
const durationMs = performance.now() - startedAt;
|
|
1336
|
+
const overBudget = durationMs > budgetMs;
|
|
1337
|
+
if (overBudget) {
|
|
1338
|
+
SYNC_CONFIG_OVER_BUDGET_BY_RUNTIME.set(baseRuntime, true);
|
|
1339
|
+
}
|
|
1340
|
+
return {
|
|
1341
|
+
snapshot,
|
|
1342
|
+
version: 1,
|
|
1343
|
+
loaded: !overBudget,
|
|
1344
|
+
loadMode: "sync",
|
|
1345
|
+
syncDurationMs: durationMs,
|
|
1346
|
+
syncOverBudget: overBudget
|
|
1347
|
+
};
|
|
1348
|
+
} catch {
|
|
1349
|
+
return { snapshot: DEFAULT_CONFIG_SNAPSHOT, version: 1, loaded: false, loadMode: "none" };
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
(0, import_react4.useEffect)(() => {
|
|
1353
|
+
if (configState.loadMode !== "sync") {
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
if (didReportSyncConfigSnapshotRef.current) {
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
didReportSyncConfigSnapshotRef.current = true;
|
|
1360
|
+
void runtimeWithBindings.runPromise(
|
|
1361
|
+
Logix5.Debug.record({
|
|
1362
|
+
type: "trace:react.runtime.config.snapshot",
|
|
1363
|
+
data: {
|
|
1364
|
+
source: configState.snapshot.source,
|
|
1365
|
+
mode: "sync",
|
|
1366
|
+
durationMs: configState.syncDurationMs !== void 0 ? Math.round(configState.syncDurationMs * 100) / 100 : void 0,
|
|
1367
|
+
syncBudgetMs: resolvedPolicy.syncBudgetMs,
|
|
1368
|
+
overBudget: Boolean(configState.syncOverBudget)
|
|
1369
|
+
}
|
|
1370
|
+
})
|
|
1371
|
+
).catch(() => {
|
|
1372
|
+
});
|
|
1373
|
+
}, [configState, resolvedPolicy.syncBudgetMs, runtimeWithBindings]);
|
|
1374
|
+
(0, import_react4.useEffect)(() => {
|
|
1375
|
+
let cancelled = false;
|
|
1376
|
+
runtimeWithBindings.runPromise(ReactRuntimeConfigSnapshot.load).then((snapshot) => {
|
|
1377
|
+
if (cancelled) return;
|
|
1378
|
+
setConfigState((prev) => {
|
|
1379
|
+
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;
|
|
1380
|
+
if (sameSnapshot && prev.loaded) {
|
|
1381
|
+
return prev;
|
|
1382
|
+
}
|
|
1383
|
+
const cacheCriticalChanged = prev.snapshot.gcTime !== snapshot.gcTime;
|
|
1384
|
+
return {
|
|
1385
|
+
snapshot,
|
|
1386
|
+
version: cacheCriticalChanged ? prev.version + 1 : prev.version,
|
|
1387
|
+
loaded: true,
|
|
1388
|
+
loadMode: "async"
|
|
1389
|
+
};
|
|
1390
|
+
});
|
|
1391
|
+
void runtimeWithBindings.runPromise(
|
|
1392
|
+
Logix5.Debug.record({
|
|
1393
|
+
type: "trace:react.runtime.config.snapshot",
|
|
1394
|
+
data: {
|
|
1395
|
+
source: snapshot.source,
|
|
1396
|
+
mode: "async"
|
|
1397
|
+
}
|
|
1398
|
+
})
|
|
1399
|
+
).catch(() => {
|
|
1400
|
+
});
|
|
1401
|
+
}).catch((error) => {
|
|
1402
|
+
if (cancelled) return;
|
|
1403
|
+
console.debug("[RuntimeProvider] Failed to load React runtime config snapshot, fallback to default.", error);
|
|
1404
|
+
setConfigState((prev) => ({
|
|
1405
|
+
snapshot: DEFAULT_CONFIG_SNAPSHOT,
|
|
1406
|
+
version: prev.version,
|
|
1407
|
+
loaded: true,
|
|
1408
|
+
loadMode: "async"
|
|
1409
|
+
}));
|
|
1410
|
+
});
|
|
1411
|
+
return () => {
|
|
1412
|
+
cancelled = true;
|
|
1413
|
+
};
|
|
1414
|
+
}, [runtimeWithBindings]);
|
|
1415
|
+
const contextValue = (0, import_react4.useMemo)(
|
|
1416
|
+
() => ({
|
|
1417
|
+
runtime: runtimeWithBindings,
|
|
1418
|
+
reactConfigSnapshot: configState.snapshot,
|
|
1419
|
+
configVersion: configState.version,
|
|
1420
|
+
policy: resolvedPolicy
|
|
1421
|
+
}),
|
|
1422
|
+
[runtimeWithBindings, configState, resolvedPolicy]
|
|
1423
|
+
);
|
|
1424
|
+
const isLayerReady = !layer || layerBinding !== null;
|
|
1425
|
+
const isConfigReady = configState.loaded;
|
|
1426
|
+
const resolveFallback = (phase) => {
|
|
1427
|
+
return resolveRuntimeProviderFallback({ fallback, phase, policyMode: resolvedPolicy.mode });
|
|
1428
|
+
};
|
|
1429
|
+
const [deferReady, setDeferReady] = (0, import_react4.useState)(false);
|
|
1430
|
+
(0, import_react4.useEffect)(() => {
|
|
1431
|
+
if (resolvedPolicy.mode !== "defer") {
|
|
1432
|
+
setDeferReady(false);
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
setDeferReady(false);
|
|
1436
|
+
}, [resolvedPolicy.mode]);
|
|
1437
|
+
const preloadCancelsRef = import_react4.default.useRef(null);
|
|
1438
|
+
(0, import_react4.useEffect)(() => {
|
|
1439
|
+
if (resolvedPolicy.mode !== "defer") {
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
setDeferReady(false);
|
|
1443
|
+
if (!resolvedPolicy.preload) {
|
|
1444
|
+
setDeferReady(true);
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
if (!isLayerReady || !isConfigReady) {
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
let cancelled = false;
|
|
1451
|
+
const cache = getModuleCache(runtimeWithBindings, configState.snapshot, configState.version);
|
|
1452
|
+
const preloadHandles = resolvedPolicy.preload.handles;
|
|
1453
|
+
if (preloadHandles.length === 0) {
|
|
1454
|
+
setDeferReady(true);
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
const concurrency = Math.max(1, resolvedPolicy.preload.concurrency ?? DEFAULT_PRELOAD_CONCURRENCY);
|
|
1458
|
+
const allCancels = /* @__PURE__ */ new Set();
|
|
1459
|
+
preloadCancelsRef.current = allCancels;
|
|
1460
|
+
const run = async () => {
|
|
1461
|
+
const queue = preloadHandles.slice();
|
|
1462
|
+
const runOne = async (handle) => {
|
|
1463
|
+
if (cancelled) return;
|
|
1464
|
+
const startedAt = performance.now();
|
|
1465
|
+
if (handle?._tag === "ModuleImpl") {
|
|
1466
|
+
const moduleId = handle.module?.id ?? "ModuleImpl";
|
|
1467
|
+
const key2 = resolvedPolicy.preload.keysByModuleId.get(moduleId) ?? getPreloadKeyForModuleId(moduleId);
|
|
1468
|
+
const factory2 = (scope) => import_effect5.Layer.buildWithScope(handle.layer, scope).pipe(
|
|
1469
|
+
import_effect5.Effect.map((context) => import_effect5.Context.get(context, handle.module))
|
|
1470
|
+
);
|
|
1471
|
+
const op2 = cache.preload(key2, factory2, {
|
|
1472
|
+
ownerId: moduleId,
|
|
1473
|
+
yield: resolvedPolicy.preload.yield,
|
|
1474
|
+
entrypoint: "react.runtime.preload",
|
|
1475
|
+
policyMode: "defer"
|
|
1476
|
+
});
|
|
1477
|
+
allCancels.add(op2.cancel);
|
|
1478
|
+
await op2.promise;
|
|
1479
|
+
const durationMs2 = performance.now() - startedAt;
|
|
1480
|
+
void runtimeWithBindings.runPromise(
|
|
1481
|
+
Logix5.Debug.record({
|
|
1482
|
+
type: "trace:react.module.preload",
|
|
1483
|
+
moduleId,
|
|
1484
|
+
data: {
|
|
1485
|
+
mode: "defer",
|
|
1486
|
+
handleKind: "ModuleImpl",
|
|
1487
|
+
key: key2,
|
|
1488
|
+
durationMs: Math.round(durationMs2 * 100) / 100,
|
|
1489
|
+
concurrency,
|
|
1490
|
+
yieldStrategy: resolvedPolicy.preload.yield.strategy,
|
|
1491
|
+
yieldOnlyWhenOverBudgetMs: resolvedPolicy.preload.yield.onlyWhenOverBudgetMs
|
|
1492
|
+
}
|
|
1493
|
+
})
|
|
1494
|
+
).catch(() => {
|
|
1495
|
+
});
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
const tagId = handle.id ?? "ModuleTag";
|
|
1499
|
+
const key = resolvedPolicy.preload.keysByTagId.get(tagId) ?? getPreloadKeyForTagId(tagId);
|
|
1500
|
+
const factory = (scope) => handle.pipe(
|
|
1501
|
+
import_effect5.Scope.extend(scope)
|
|
1502
|
+
);
|
|
1503
|
+
const op = cache.preload(key, factory, {
|
|
1504
|
+
ownerId: tagId,
|
|
1505
|
+
yield: resolvedPolicy.preload.yield,
|
|
1506
|
+
entrypoint: "react.runtime.preload",
|
|
1507
|
+
policyMode: "defer"
|
|
1508
|
+
});
|
|
1509
|
+
allCancels.add(op.cancel);
|
|
1510
|
+
await op.promise;
|
|
1511
|
+
const durationMs = performance.now() - startedAt;
|
|
1512
|
+
void runtimeWithBindings.runPromise(
|
|
1513
|
+
Logix5.Debug.record({
|
|
1514
|
+
type: "trace:react.module.preload",
|
|
1515
|
+
data: {
|
|
1516
|
+
mode: "defer",
|
|
1517
|
+
handleKind: "ModuleTag",
|
|
1518
|
+
tokenId: tagId,
|
|
1519
|
+
key,
|
|
1520
|
+
durationMs: Math.round(durationMs * 100) / 100,
|
|
1521
|
+
concurrency,
|
|
1522
|
+
yieldStrategy: resolvedPolicy.preload.yield.strategy,
|
|
1523
|
+
yieldOnlyWhenOverBudgetMs: resolvedPolicy.preload.yield.onlyWhenOverBudgetMs
|
|
1524
|
+
}
|
|
1525
|
+
})
|
|
1526
|
+
).catch(() => {
|
|
1527
|
+
});
|
|
1528
|
+
};
|
|
1529
|
+
const workers = Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
|
|
1530
|
+
while (!cancelled) {
|
|
1531
|
+
const next = queue.shift();
|
|
1532
|
+
if (!next) return;
|
|
1533
|
+
await runOne(next);
|
|
1534
|
+
}
|
|
1535
|
+
});
|
|
1536
|
+
await Promise.all(workers);
|
|
1537
|
+
};
|
|
1538
|
+
run().then(() => {
|
|
1539
|
+
if (cancelled) return;
|
|
1540
|
+
setDeferReady(true);
|
|
1541
|
+
}).catch((error) => {
|
|
1542
|
+
if (cancelled) return;
|
|
1543
|
+
if (onErrorRef.current) {
|
|
1544
|
+
runtimeWithBindings.runFork(
|
|
1545
|
+
onErrorRef.current(import_effect5.Cause.die(error), { source: "provider", phase: "provider.layer.build" }).pipe(import_effect5.Effect.catchAllCause(() => import_effect5.Effect.void))
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
setDeferReady(true);
|
|
1549
|
+
});
|
|
1550
|
+
return () => {
|
|
1551
|
+
cancelled = true;
|
|
1552
|
+
preloadCancelsRef.current = null;
|
|
1553
|
+
for (const cancel of allCancels) cancel();
|
|
1554
|
+
};
|
|
1555
|
+
}, [resolvedPolicy, isLayerReady, isConfigReady, runtimeWithBindings, configState, onErrorRef]);
|
|
1556
|
+
(0, import_react4.useEffect)(() => {
|
|
1557
|
+
if (resolvedPolicy.mode !== "defer" || !deferReady) {
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
const cancels = preloadCancelsRef.current;
|
|
1561
|
+
if (!cancels || cancels.size === 0) {
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
preloadCancelsRef.current = null;
|
|
1565
|
+
const list = Array.from(cancels);
|
|
1566
|
+
let released = false;
|
|
1567
|
+
const release = () => {
|
|
1568
|
+
if (released) return;
|
|
1569
|
+
released = true;
|
|
1570
|
+
for (const cancel of list) cancel();
|
|
1571
|
+
};
|
|
1572
|
+
const timeout = setTimeout(release, 0);
|
|
1573
|
+
return () => {
|
|
1574
|
+
clearTimeout(timeout);
|
|
1575
|
+
release();
|
|
1576
|
+
};
|
|
1577
|
+
}, [resolvedPolicy.mode, deferReady]);
|
|
1578
|
+
const isReady = isLayerReady && isConfigReady && (resolvedPolicy.mode !== "defer" || deferReady);
|
|
1579
|
+
if (!isReady) {
|
|
1580
|
+
const blockersList = [
|
|
1581
|
+
isLayerReady ? null : "layer",
|
|
1582
|
+
isConfigReady ? null : "config",
|
|
1583
|
+
resolvedPolicy.mode !== "defer" || deferReady ? null : "preload"
|
|
1584
|
+
].filter((x) => x !== null);
|
|
1585
|
+
const blockers = blockersList.length > 0 ? blockersList.join("+") : void 0;
|
|
1586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1587
|
+
FallbackProbe,
|
|
1588
|
+
{
|
|
1589
|
+
runtime: runtimeWithBindings,
|
|
1590
|
+
phase: "provider.gating",
|
|
1591
|
+
policyMode: resolvedPolicy.mode,
|
|
1592
|
+
blockers,
|
|
1593
|
+
children: resolveFallback("provider.gating")
|
|
1594
|
+
}
|
|
1595
|
+
);
|
|
1596
|
+
}
|
|
1597
|
+
const content = resolvedPolicy.mode === "sync" ? children : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1598
|
+
import_react4.default.Suspense,
|
|
1599
|
+
{
|
|
1600
|
+
fallback: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FallbackProbe, { runtime: runtimeWithBindings, phase: "react.suspense", policyMode: resolvedPolicy.mode, children: resolveFallback("react.suspense") }),
|
|
1601
|
+
children
|
|
1602
|
+
}
|
|
1603
|
+
);
|
|
1604
|
+
return import_react4.default.createElement(RuntimeContext.Provider, { value: contextValue }, content);
|
|
1605
|
+
};
|
|
1606
|
+
var useRuntimeResolution = (runtimeProp, parent) => {
|
|
1607
|
+
const baseRuntime = runtimeProp ?? parent?.runtime;
|
|
1608
|
+
if (!baseRuntime) {
|
|
1609
|
+
throw new Error(
|
|
1610
|
+
"[RuntimeProvider] Missing runtime.\n\nFix:\n- Provide `runtime` prop: <RuntimeProvider runtime={runtime}>...\n- Or nest under an ancestor RuntimeProvider that provides `runtime`.\n"
|
|
1611
|
+
);
|
|
1612
|
+
}
|
|
1613
|
+
return baseRuntime;
|
|
1614
|
+
};
|
|
1615
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1616
|
+
0 && (module.exports = {
|
|
1617
|
+
RuntimeProvider
|
|
1618
|
+
});
|