@logixjs/react 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +1 -1
- package/dist/Hooks.cjs +462 -325
- package/dist/Hooks.d.cts +6 -6
- package/dist/Hooks.d.ts +6 -6
- package/dist/Hooks.js +3 -3
- package/dist/{ModuleRef-wZSQ3Wwo.d.cts → ModuleRef-gZmL6Zvb.d.cts} +8 -3
- package/dist/{ModuleRef-wZSQ3Wwo.d.ts → ModuleRef-gZmL6Zvb.d.ts} +8 -3
- package/dist/ModuleScope.cjs +596 -362
- package/dist/ModuleScope.d.cts +4 -4
- package/dist/ModuleScope.d.ts +4 -4
- package/dist/ModuleScope.js +4 -4
- package/dist/Platform.cjs +1 -4
- package/dist/Platform.d.cts +1 -2
- package/dist/Platform.d.ts +1 -2
- package/dist/Platform.js +1 -1
- package/dist/ReactPlatform.cjs +543 -309
- package/dist/ReactPlatform.d.cts +2 -2
- package/dist/ReactPlatform.d.ts +2 -2
- package/dist/ReactPlatform.js +5 -5
- package/dist/RuntimeProvider.cjs +276 -56
- package/dist/RuntimeProvider.js +2 -2
- package/dist/{chunk-PYWHL7TA.js → chunk-6NLXTHZ7.js} +8 -8
- package/dist/{chunk-UFFCJGSZ.js → chunk-E3ZXST5F.js} +256 -240
- package/dist/{chunk-4G7H66OY.js → chunk-KYWW4KMQ.js} +3 -3
- package/dist/{chunk-2WFULYPJ.js → chunk-L7KTYBXN.js} +155 -32
- package/dist/{chunk-ZANGOPUQ.js → chunk-NKYV44OG.js} +1 -4
- package/dist/{chunk-G5MRIFKK.js → chunk-SDQF3WRT.js} +7 -7
- package/dist/{chunk-JXAJTWSZ.js → chunk-XSGDBJXD.js} +122 -25
- package/dist/index.cjs +564 -333
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -7
- package/dist/{useDispatch-BnzYVkRE.d.ts → useDispatch-CiDimIYZ.d.ts} +13 -15
- package/dist/{useDispatch-CnO5-66H.d.cts → useDispatch-DiwQQAfC.d.cts} +13 -15
- package/package.json +12 -4
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
isDevEnv,
|
|
6
6
|
stableHash,
|
|
7
7
|
useLayerBinding
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-L7KTYBXN.js";
|
|
9
9
|
|
|
10
10
|
// src/internal/hooks/useRuntime.ts
|
|
11
11
|
import { useContext, useEffect, useMemo, useRef } from "react";
|
|
@@ -138,12 +138,12 @@ var shallow = (previous, next) => {
|
|
|
138
138
|
// src/internal/hooks/useSelector.ts
|
|
139
139
|
import { useContext as useContext3, useEffect as useEffect3, useMemo as useMemo3 } from "react";
|
|
140
140
|
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector";
|
|
141
|
-
import * as
|
|
141
|
+
import * as Logix4 from "@logixjs/core";
|
|
142
142
|
|
|
143
143
|
// src/internal/hooks/useModuleRuntime.ts
|
|
144
|
-
import { useEffect as useEffect2, useMemo as useMemo2, useContext as useContext2 } from "react";
|
|
145
|
-
import * as
|
|
146
|
-
import { Scope } from "effect";
|
|
144
|
+
import { useEffect as useEffect2, useMemo as useMemo2, useContext as useContext2, useRef as useRef2 } from "react";
|
|
145
|
+
import * as Logix2 from "@logixjs/core";
|
|
146
|
+
import { Effect as Effect2, Scope } from "effect";
|
|
147
147
|
|
|
148
148
|
// src/internal/store/ModuleRef.ts
|
|
149
149
|
var isModuleRef = (value) => typeof value === "object" && value !== null && "runtime" in value && "actions" in value && "dispatch" in value;
|
|
@@ -234,11 +234,26 @@ var applyHandleExtend = (tag, runtime, base) => {
|
|
|
234
234
|
return { ...base, ...next };
|
|
235
235
|
};
|
|
236
236
|
|
|
237
|
+
// src/internal/provider/runtimeDebugBridge.ts
|
|
238
|
+
import { Effect } from "effect";
|
|
239
|
+
import * as Logix from "@logixjs/core";
|
|
240
|
+
var readRuntimeDiagnosticsLevel = (runtime) => {
|
|
241
|
+
try {
|
|
242
|
+
return runtime.runSync(Effect.service(Logix.Debug.internal.currentDiagnosticsLevel).pipe(Effect.orDie));
|
|
243
|
+
} catch {
|
|
244
|
+
return isDevEnv() ? "light" : "off";
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
var emitRuntimeDebugEventBestEffort = (runtime, event) => {
|
|
248
|
+
runtime.runFork(event);
|
|
249
|
+
};
|
|
250
|
+
|
|
237
251
|
// src/internal/hooks/useModuleRuntime.ts
|
|
238
252
|
var isModuleRuntime = (value) => typeof value === "object" && value !== null && "dispatch" in value && "getState" in value;
|
|
239
253
|
function useModuleRuntime(handle) {
|
|
240
254
|
const runtime = useRuntime();
|
|
241
255
|
const runtimeContext = useContext2(RuntimeContext);
|
|
256
|
+
const moduleTagResolveTraceRef = useRef2(void 0);
|
|
242
257
|
if (!runtimeContext) {
|
|
243
258
|
throw new RuntimeProviderNotFoundError("useModuleRuntime");
|
|
244
259
|
}
|
|
@@ -259,87 +274,117 @@ function useModuleRuntime(handle) {
|
|
|
259
274
|
const preloadKey = runtimeContext.policy.preload?.keysByTagId.get(tokenId);
|
|
260
275
|
const key = preloadKey ?? `tag:${tokenId}`;
|
|
261
276
|
const mode = runtimeContext.policy.moduleTagMode;
|
|
262
|
-
const
|
|
263
|
-
|
|
277
|
+
const startedAtMs = performance.now();
|
|
278
|
+
const factory = (scope) => Scope.provide(scope)(Effect2.service(tag).pipe(Effect2.orDie));
|
|
279
|
+
const resolvedRuntime = mode === "suspend" ? cache.read(key, factory, void 0, tokenId, {
|
|
264
280
|
entrypoint: "react.useModuleRuntime",
|
|
265
281
|
policyMode: runtimeContext.policy.mode,
|
|
266
|
-
yield: runtimeContext.policy.yield
|
|
282
|
+
yield: runtimeContext.policy.yield,
|
|
283
|
+
optimisticSyncBudgetMs: runtimeContext.policy.syncBudgetMs
|
|
267
284
|
}) : cache.readSync(key, factory, void 0, tokenId, {
|
|
268
285
|
entrypoint: "react.useModuleRuntime",
|
|
269
286
|
policyMode: runtimeContext.policy.mode,
|
|
270
287
|
warnSyncBlockingThresholdMs: 5
|
|
271
288
|
});
|
|
289
|
+
moduleTagResolveTraceRef.current = {
|
|
290
|
+
tokenId,
|
|
291
|
+
durationMs: Math.round((performance.now() - startedAtMs) * 100) / 100,
|
|
292
|
+
cacheMode: mode
|
|
293
|
+
};
|
|
294
|
+
return resolvedRuntime;
|
|
272
295
|
}, [cache, runtimeContext.policy, handle]);
|
|
273
296
|
useEffect2(() => {
|
|
274
297
|
if (!isTagHandle) {
|
|
275
298
|
return;
|
|
276
299
|
}
|
|
277
|
-
|
|
300
|
+
const diagnosticsLevel = readRuntimeDiagnosticsLevel(runtime);
|
|
301
|
+
if (diagnosticsLevel === "off") {
|
|
278
302
|
return;
|
|
279
303
|
}
|
|
280
304
|
const tokenId = handle?.id ?? "ModuleTag";
|
|
281
|
-
const
|
|
305
|
+
const trace = moduleTagResolveTraceRef.current;
|
|
306
|
+
const effect = Logix2.Debug.record({
|
|
282
307
|
type: "trace:react.moduleTag.resolve",
|
|
283
308
|
moduleId: resolved.moduleId,
|
|
284
309
|
instanceId: resolved.instanceId,
|
|
285
310
|
data: {
|
|
286
311
|
mode: runtimeContext.policy.moduleTagMode,
|
|
287
312
|
tokenId,
|
|
288
|
-
yieldStrategy: runtimeContext.policy.yield.strategy
|
|
313
|
+
yieldStrategy: runtimeContext.policy.yield.strategy,
|
|
314
|
+
durationMs: trace?.durationMs,
|
|
315
|
+
cacheMode: trace?.cacheMode ?? runtimeContext.policy.moduleTagMode
|
|
289
316
|
}
|
|
290
317
|
});
|
|
291
|
-
runtime
|
|
318
|
+
emitRuntimeDebugEventBestEffort(runtime, effect);
|
|
292
319
|
}, [runtime, runtimeContext.policy, resolved, handle, isTagHandle]);
|
|
293
320
|
return resolved;
|
|
294
321
|
}
|
|
295
322
|
|
|
296
|
-
// src/internal/store/
|
|
297
|
-
import
|
|
323
|
+
// src/internal/store/RuntimeExternalStore.ts
|
|
324
|
+
import * as Logix3 from "@logixjs/core";
|
|
325
|
+
import { Fiber, Stream } from "effect";
|
|
298
326
|
var storesByRuntime = /* @__PURE__ */ new WeakMap();
|
|
299
327
|
var getStoreMapForRuntime = (runtime) => {
|
|
300
328
|
const cached = storesByRuntime.get(runtime);
|
|
301
329
|
if (cached) return cached;
|
|
302
|
-
const next = /* @__PURE__ */ new
|
|
330
|
+
const next = /* @__PURE__ */ new Map();
|
|
303
331
|
storesByRuntime.set(runtime, next);
|
|
304
332
|
return next;
|
|
305
333
|
};
|
|
306
|
-
var
|
|
307
|
-
|
|
308
|
-
|
|
334
|
+
var makeModuleInstanceKey = (moduleId, instanceId) => `${moduleId}::${instanceId}`;
|
|
335
|
+
var makeReadQueryTopicKey = (moduleInstanceKey, selectorId) => `${moduleInstanceKey}::rq:${selectorId}`;
|
|
336
|
+
var getRuntimeStore = (runtime) => Logix3.InternalContracts.getRuntimeStore(runtime);
|
|
337
|
+
var getHostScheduler = (runtime) => Logix3.InternalContracts.getHostScheduler(runtime);
|
|
338
|
+
var getOrCreateStore = (runtime, topicKey, make) => {
|
|
339
|
+
const map = getStoreMapForRuntime(runtime);
|
|
340
|
+
const cached = map.get(topicKey);
|
|
309
341
|
if (cached) {
|
|
310
342
|
return cached;
|
|
311
343
|
}
|
|
312
|
-
|
|
344
|
+
const created = make();
|
|
345
|
+
map.set(topicKey, created);
|
|
346
|
+
return created;
|
|
347
|
+
};
|
|
348
|
+
var removeStore = (runtime, topicKey) => {
|
|
349
|
+
const map = storesByRuntime.get(runtime);
|
|
350
|
+
if (!map) return;
|
|
351
|
+
map.delete(topicKey);
|
|
352
|
+
};
|
|
353
|
+
var makeTopicExternalStore = (args) => {
|
|
354
|
+
const { runtime, runtimeStore, topicKey } = args;
|
|
355
|
+
const hostScheduler = getHostScheduler(runtime);
|
|
356
|
+
let currentVersion;
|
|
357
|
+
let hasSnapshot = false;
|
|
358
|
+
let currentSnapshot;
|
|
313
359
|
const listeners = /* @__PURE__ */ new Set();
|
|
314
|
-
|
|
315
|
-
|
|
360
|
+
let unsubscribeFromRuntimeStore;
|
|
361
|
+
let teardownScheduled = false;
|
|
362
|
+
let teardownToken = 0;
|
|
363
|
+
const lowPriorityDelayMs = args.options?.lowPriorityDelayMs ?? 16;
|
|
364
|
+
const lowPriorityMaxDelayMs = args.options?.lowPriorityMaxDelayMs ?? 50;
|
|
316
365
|
let notifyScheduled = false;
|
|
317
366
|
let notifyScheduledLow = false;
|
|
318
|
-
let
|
|
319
|
-
let
|
|
320
|
-
let
|
|
367
|
+
let lowCancelDelay;
|
|
368
|
+
let lowCancelMaxDelay;
|
|
369
|
+
let lowCancelRaf;
|
|
321
370
|
const cancelLow = () => {
|
|
322
371
|
if (!notifyScheduledLow) return;
|
|
323
372
|
notifyScheduledLow = false;
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
lowMaxTimeoutId = void 0;
|
|
331
|
-
}
|
|
332
|
-
const cancel = globalThis.cancelAnimationFrame;
|
|
333
|
-
if (cancel && typeof lowRafId === "number") {
|
|
334
|
-
cancel(lowRafId);
|
|
335
|
-
lowRafId = void 0;
|
|
336
|
-
}
|
|
373
|
+
lowCancelDelay?.();
|
|
374
|
+
lowCancelDelay = void 0;
|
|
375
|
+
lowCancelMaxDelay?.();
|
|
376
|
+
lowCancelMaxDelay = void 0;
|
|
377
|
+
lowCancelRaf?.();
|
|
378
|
+
lowCancelRaf = void 0;
|
|
337
379
|
};
|
|
338
380
|
const flushNotify = () => {
|
|
339
381
|
notifyScheduled = false;
|
|
340
382
|
cancelLow();
|
|
341
383
|
for (const listener of listeners) {
|
|
342
|
-
|
|
384
|
+
try {
|
|
385
|
+
listener();
|
|
386
|
+
} catch {
|
|
387
|
+
}
|
|
343
388
|
}
|
|
344
389
|
};
|
|
345
390
|
const scheduleNotify = (priority) => {
|
|
@@ -351,209 +396,154 @@ var getModuleRuntimeExternalStore = (runtime, moduleRuntime, options) => {
|
|
|
351
396
|
if (!notifyScheduledLow) return;
|
|
352
397
|
flushNotify();
|
|
353
398
|
};
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
399
|
+
const scheduleRaf = () => {
|
|
400
|
+
if (!notifyScheduledLow) return;
|
|
401
|
+
lowCancelRaf = hostScheduler.scheduleAnimationFrame(flush);
|
|
402
|
+
};
|
|
403
|
+
if (lowPriorityDelayMs <= 0) {
|
|
404
|
+
scheduleRaf();
|
|
357
405
|
} else {
|
|
358
|
-
|
|
406
|
+
lowCancelDelay = hostScheduler.scheduleTimeout(lowPriorityDelayMs, scheduleRaf);
|
|
359
407
|
}
|
|
360
|
-
|
|
408
|
+
lowCancelMaxDelay = hostScheduler.scheduleTimeout(lowPriorityMaxDelayMs, flush);
|
|
361
409
|
return;
|
|
362
410
|
}
|
|
363
411
|
cancelLow();
|
|
364
412
|
if (notifyScheduled) return;
|
|
365
413
|
notifyScheduled = true;
|
|
366
|
-
|
|
414
|
+
hostScheduler.scheduleMicrotask(flushNotify);
|
|
415
|
+
};
|
|
416
|
+
const onRuntimeStoreChange = () => {
|
|
417
|
+
try {
|
|
418
|
+
scheduleNotify(runtimeStore.getTopicPriority(topicKey));
|
|
419
|
+
} catch {
|
|
420
|
+
}
|
|
367
421
|
};
|
|
368
|
-
let fiber;
|
|
369
422
|
const ensureSubscription = () => {
|
|
370
|
-
if (
|
|
371
|
-
|
|
372
|
-
Stream.runForEach(
|
|
373
|
-
moduleRuntime.changesWithMeta((state) => state),
|
|
374
|
-
({ value: state, meta }) => Effect2.sync(() => {
|
|
375
|
-
currentState = state;
|
|
376
|
-
scheduleNotify(meta.priority);
|
|
377
|
-
})
|
|
378
|
-
)
|
|
379
|
-
);
|
|
423
|
+
if (unsubscribeFromRuntimeStore) return;
|
|
424
|
+
unsubscribeFromRuntimeStore = runtimeStore.subscribeTopic(topicKey, onRuntimeStoreChange);
|
|
380
425
|
};
|
|
381
426
|
const refreshSnapshotIfStale = () => {
|
|
382
|
-
if (
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
427
|
+
if (!hasSnapshot) return;
|
|
385
428
|
try {
|
|
386
|
-
const
|
|
387
|
-
if (
|
|
388
|
-
|
|
389
|
-
scheduleNotify("normal");
|
|
429
|
+
const version = runtimeStore.getTopicVersion(topicKey);
|
|
430
|
+
if (currentVersion !== version) {
|
|
431
|
+
scheduleNotify(runtimeStore.getTopicPriority(topicKey));
|
|
390
432
|
}
|
|
391
433
|
} catch {
|
|
392
434
|
}
|
|
393
435
|
};
|
|
394
436
|
const getSnapshot = () => {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
return
|
|
404
|
-
listeners.delete(listener);
|
|
405
|
-
if (listeners.size > 0) return;
|
|
406
|
-
const running = fiber;
|
|
407
|
-
if (!running) return;
|
|
408
|
-
fiber = void 0;
|
|
409
|
-
cancelLow();
|
|
410
|
-
runtime.runFork(Fiber.interrupt(running));
|
|
411
|
-
};
|
|
437
|
+
const version = runtimeStore.getTopicVersion(topicKey);
|
|
438
|
+
if (hasSnapshot && currentVersion === version) {
|
|
439
|
+
return currentSnapshot;
|
|
440
|
+
}
|
|
441
|
+
const next = args.readSnapshot();
|
|
442
|
+
currentVersion = version;
|
|
443
|
+
hasSnapshot = true;
|
|
444
|
+
currentSnapshot = next;
|
|
445
|
+
return next;
|
|
412
446
|
};
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
// src/internal/store/ModuleRuntimeSelectorExternalStore.ts
|
|
419
|
-
import { Effect as Effect3, Fiber as Fiber2, Stream as Stream2 } from "effect";
|
|
420
|
-
var storesByRuntime2 = /* @__PURE__ */ new WeakMap();
|
|
421
|
-
var getStoreMapForRuntime2 = (runtime) => {
|
|
422
|
-
const cached = storesByRuntime2.get(runtime);
|
|
423
|
-
if (cached) return cached;
|
|
424
|
-
const next = /* @__PURE__ */ new WeakMap();
|
|
425
|
-
storesByRuntime2.set(runtime, next);
|
|
426
|
-
return next;
|
|
427
|
-
};
|
|
428
|
-
var getOrCreateSelectorMapForModule = (byModule, moduleRuntime) => {
|
|
429
|
-
const cached = byModule.get(moduleRuntime);
|
|
430
|
-
if (cached) return cached;
|
|
431
|
-
const next = /* @__PURE__ */ new Map();
|
|
432
|
-
byModule.set(moduleRuntime, next);
|
|
433
|
-
return next;
|
|
434
|
-
};
|
|
435
|
-
var equalsValue = (readQuery, a, b) => {
|
|
436
|
-
if (readQuery.equalsKind === "custom" && typeof readQuery.equals === "function") {
|
|
437
|
-
return readQuery.equals(a, b);
|
|
438
|
-
}
|
|
439
|
-
if (readQuery.equalsKind === "shallowStruct") {
|
|
440
|
-
return shallow(a, b);
|
|
441
|
-
}
|
|
442
|
-
return Object.is(a, b);
|
|
443
|
-
};
|
|
444
|
-
var getModuleRuntimeSelectorExternalStore = (runtime, moduleRuntime, selectorReadQuery, options) => {
|
|
445
|
-
const byModule = getStoreMapForRuntime2(runtime);
|
|
446
|
-
const bySelector = getOrCreateSelectorMapForModule(byModule, moduleRuntime);
|
|
447
|
-
const cached = bySelector.get(selectorReadQuery.selectorId);
|
|
448
|
-
if (cached) {
|
|
449
|
-
return cached;
|
|
450
|
-
}
|
|
451
|
-
let currentValue;
|
|
452
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
453
|
-
const lowPriorityDelayMs = options?.lowPriorityDelayMs ?? 16;
|
|
454
|
-
const lowPriorityMaxDelayMs = options?.lowPriorityMaxDelayMs ?? 50;
|
|
455
|
-
let notifyScheduled = false;
|
|
456
|
-
let notifyScheduledLow = false;
|
|
457
|
-
let lowTimeoutId;
|
|
458
|
-
let lowMaxTimeoutId;
|
|
459
|
-
let lowRafId;
|
|
460
|
-
const cancelLow = () => {
|
|
461
|
-
if (!notifyScheduledLow) return;
|
|
462
|
-
notifyScheduledLow = false;
|
|
463
|
-
if (lowTimeoutId != null) {
|
|
464
|
-
clearTimeout(lowTimeoutId);
|
|
465
|
-
lowTimeoutId = void 0;
|
|
466
|
-
}
|
|
467
|
-
if (lowMaxTimeoutId != null) {
|
|
468
|
-
clearTimeout(lowMaxTimeoutId);
|
|
469
|
-
lowMaxTimeoutId = void 0;
|
|
470
|
-
}
|
|
471
|
-
const cancel = globalThis.cancelAnimationFrame;
|
|
472
|
-
if (cancel && typeof lowRafId === "number") {
|
|
473
|
-
cancel(lowRafId);
|
|
474
|
-
lowRafId = void 0;
|
|
475
|
-
}
|
|
447
|
+
const cancelScheduledTeardown = () => {
|
|
448
|
+
if (!teardownScheduled) return;
|
|
449
|
+
teardownScheduled = false;
|
|
450
|
+
teardownToken += 1;
|
|
476
451
|
};
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
};
|
|
484
|
-
const scheduleNotify = (priority) => {
|
|
485
|
-
if (priority === "low") {
|
|
486
|
-
if (notifyScheduled) return;
|
|
487
|
-
if (notifyScheduledLow) return;
|
|
488
|
-
notifyScheduledLow = true;
|
|
489
|
-
const flush = () => {
|
|
490
|
-
if (!notifyScheduledLow) return;
|
|
491
|
-
flushNotify();
|
|
492
|
-
};
|
|
493
|
-
const raf = globalThis.requestAnimationFrame;
|
|
494
|
-
if (raf) {
|
|
495
|
-
lowRafId = raf(flush);
|
|
496
|
-
} else {
|
|
497
|
-
lowTimeoutId = setTimeout(flush, lowPriorityDelayMs);
|
|
498
|
-
}
|
|
499
|
-
lowMaxTimeoutId = setTimeout(flush, lowPriorityMaxDelayMs);
|
|
500
|
-
return;
|
|
452
|
+
const finalizeTeardown = () => {
|
|
453
|
+
if (listeners.size > 0) return;
|
|
454
|
+
try {
|
|
455
|
+
args.onLastListener?.();
|
|
456
|
+
} catch {
|
|
501
457
|
}
|
|
458
|
+
const unsub = unsubscribeFromRuntimeStore;
|
|
459
|
+
unsubscribeFromRuntimeStore = void 0;
|
|
502
460
|
cancelLow();
|
|
503
|
-
if (notifyScheduled) return;
|
|
504
|
-
notifyScheduled = true;
|
|
505
|
-
queueMicrotask(flushNotify);
|
|
506
|
-
};
|
|
507
|
-
let fiber;
|
|
508
|
-
const ensureSubscription = () => {
|
|
509
|
-
if (fiber) return;
|
|
510
|
-
fiber = runtime.runFork(
|
|
511
|
-
Stream2.runForEach(
|
|
512
|
-
moduleRuntime.changesReadQueryWithMeta(selectorReadQuery),
|
|
513
|
-
({ value, meta }) => Effect3.sync(() => {
|
|
514
|
-
currentValue = value;
|
|
515
|
-
scheduleNotify(meta.priority);
|
|
516
|
-
})
|
|
517
|
-
)
|
|
518
|
-
);
|
|
519
|
-
};
|
|
520
|
-
const refreshSnapshotIfStale = () => {
|
|
521
|
-
if (currentValue === void 0) {
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
461
|
try {
|
|
525
|
-
|
|
526
|
-
const next = selectorReadQuery.select(state);
|
|
527
|
-
if (currentValue === void 0 || !equalsValue(selectorReadQuery, currentValue, next)) {
|
|
528
|
-
currentValue = next;
|
|
529
|
-
scheduleNotify("normal");
|
|
530
|
-
}
|
|
462
|
+
unsub?.();
|
|
531
463
|
} catch {
|
|
532
464
|
}
|
|
465
|
+
removeStore(runtime, topicKey);
|
|
533
466
|
};
|
|
534
|
-
const
|
|
535
|
-
if (
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
467
|
+
const scheduleTeardown = () => {
|
|
468
|
+
if (teardownScheduled) return;
|
|
469
|
+
teardownScheduled = true;
|
|
470
|
+
const token = ++teardownToken;
|
|
471
|
+
hostScheduler.scheduleMicrotask(() => {
|
|
472
|
+
if (!teardownScheduled || token !== teardownToken) return;
|
|
473
|
+
teardownScheduled = false;
|
|
474
|
+
finalizeTeardown();
|
|
475
|
+
});
|
|
539
476
|
};
|
|
540
477
|
const subscribe = (listener) => {
|
|
478
|
+
cancelScheduledTeardown();
|
|
479
|
+
const isFirst = listeners.size === 0;
|
|
541
480
|
listeners.add(listener);
|
|
542
481
|
ensureSubscription();
|
|
543
482
|
refreshSnapshotIfStale();
|
|
483
|
+
if (isFirst) {
|
|
484
|
+
try {
|
|
485
|
+
args.onFirstListener?.();
|
|
486
|
+
} catch {
|
|
487
|
+
}
|
|
488
|
+
}
|
|
544
489
|
return () => {
|
|
545
490
|
listeners.delete(listener);
|
|
546
491
|
if (listeners.size > 0) return;
|
|
547
|
-
|
|
548
|
-
if (!running) return;
|
|
549
|
-
fiber = void 0;
|
|
550
|
-
cancelLow();
|
|
551
|
-
runtime.runFork(Fiber2.interrupt(running));
|
|
492
|
+
scheduleTeardown();
|
|
552
493
|
};
|
|
553
494
|
};
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
495
|
+
return { getSnapshot, getServerSnapshot: getSnapshot, subscribe };
|
|
496
|
+
};
|
|
497
|
+
var getRuntimeModuleExternalStore = (runtime, moduleRuntime, options) => {
|
|
498
|
+
const moduleInstanceKey = makeModuleInstanceKey(moduleRuntime.moduleId, moduleRuntime.instanceId);
|
|
499
|
+
const runtimeStore = getRuntimeStore(runtime);
|
|
500
|
+
return getOrCreateStore(
|
|
501
|
+
runtime,
|
|
502
|
+
moduleInstanceKey,
|
|
503
|
+
() => makeTopicExternalStore({
|
|
504
|
+
runtime,
|
|
505
|
+
runtimeStore,
|
|
506
|
+
topicKey: moduleInstanceKey,
|
|
507
|
+
readSnapshot: () => {
|
|
508
|
+
const state = runtimeStore.getModuleState(moduleInstanceKey);
|
|
509
|
+
if (state !== void 0) return state;
|
|
510
|
+
return runtime.runSync(moduleRuntime.getState);
|
|
511
|
+
},
|
|
512
|
+
options
|
|
513
|
+
})
|
|
514
|
+
);
|
|
515
|
+
};
|
|
516
|
+
var getRuntimeReadQueryExternalStore = (runtime, moduleRuntime, selectorReadQuery, options) => {
|
|
517
|
+
const moduleInstanceKey = makeModuleInstanceKey(moduleRuntime.moduleId, moduleRuntime.instanceId);
|
|
518
|
+
const topicKey = makeReadQueryTopicKey(moduleInstanceKey, selectorReadQuery.selectorId);
|
|
519
|
+
const runtimeStore = getRuntimeStore(runtime);
|
|
520
|
+
let readQueryDrainFiber;
|
|
521
|
+
return getOrCreateStore(
|
|
522
|
+
runtime,
|
|
523
|
+
topicKey,
|
|
524
|
+
() => makeTopicExternalStore({
|
|
525
|
+
runtime,
|
|
526
|
+
runtimeStore,
|
|
527
|
+
topicKey,
|
|
528
|
+
readSnapshot: () => {
|
|
529
|
+
const state = runtimeStore.getModuleState(moduleInstanceKey);
|
|
530
|
+
const current = state ?? runtime.runSync(moduleRuntime.getState);
|
|
531
|
+
return selectorReadQuery.select(current);
|
|
532
|
+
},
|
|
533
|
+
options,
|
|
534
|
+
onFirstListener: () => {
|
|
535
|
+
if (readQueryDrainFiber) return;
|
|
536
|
+
const effect = Stream.runDrain(moduleRuntime.changesReadQueryWithMeta(selectorReadQuery));
|
|
537
|
+
readQueryDrainFiber = runtime.runFork(effect);
|
|
538
|
+
},
|
|
539
|
+
onLastListener: () => {
|
|
540
|
+
const fiber = readQueryDrainFiber;
|
|
541
|
+
if (!fiber) return;
|
|
542
|
+
readQueryDrainFiber = void 0;
|
|
543
|
+
runtime.runFork(Fiber.interrupt(fiber));
|
|
544
|
+
}
|
|
545
|
+
})
|
|
546
|
+
);
|
|
557
547
|
};
|
|
558
548
|
|
|
559
549
|
// src/internal/hooks/useSelector.ts
|
|
@@ -566,7 +556,7 @@ function useSelector(handle, selector, equalityFn) {
|
|
|
566
556
|
const moduleRuntime = useModuleRuntime(handle);
|
|
567
557
|
const actualSelector = selector ?? ((state) => state);
|
|
568
558
|
const selectorReadQuery = useMemo3(
|
|
569
|
-
() => typeof selector === "function" ?
|
|
559
|
+
() => typeof selector === "function" ? Logix4.ReadQuery.compile(selector) : void 0,
|
|
570
560
|
[selector]
|
|
571
561
|
);
|
|
572
562
|
const actualEqualityFn = useMemo3(() => {
|
|
@@ -574,17 +564,12 @@ function useSelector(handle, selector, equalityFn) {
|
|
|
574
564
|
if (typeof selector !== "function") return Object.is;
|
|
575
565
|
return selectorReadQuery?.equalsKind === "shallowStruct" ? shallow : Object.is;
|
|
576
566
|
}, [equalityFn, selector, selectorReadQuery?.equalsKind]);
|
|
577
|
-
const
|
|
567
|
+
const selectorTopicEligible = typeof selector === "function" && selectorReadQuery?.lane === "static" && selectorReadQuery.readsDigest != null && selectorReadQuery.fallbackReason == null;
|
|
578
568
|
const store = useMemo3(
|
|
579
|
-
() =>
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
{
|
|
584
|
-
lowPriorityDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
|
|
585
|
-
lowPriorityMaxDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs
|
|
586
|
-
}
|
|
587
|
-
) : getModuleRuntimeExternalStore(
|
|
569
|
+
() => selectorTopicEligible && selectorReadQuery ? getRuntimeReadQueryExternalStore(runtime, moduleRuntime, selectorReadQuery, {
|
|
570
|
+
lowPriorityDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
|
|
571
|
+
lowPriorityMaxDelayMs: runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs
|
|
572
|
+
}) : getRuntimeModuleExternalStore(
|
|
588
573
|
runtime,
|
|
589
574
|
moduleRuntime,
|
|
590
575
|
{
|
|
@@ -598,18 +583,18 @@ function useSelector(handle, selector, equalityFn) {
|
|
|
598
583
|
runtimeContext.reactConfigSnapshot.lowPriorityDelayMs,
|
|
599
584
|
runtimeContext.reactConfigSnapshot.lowPriorityMaxDelayMs,
|
|
600
585
|
selectorReadQuery,
|
|
601
|
-
|
|
586
|
+
selectorTopicEligible
|
|
602
587
|
]
|
|
603
588
|
);
|
|
604
589
|
const selected = useSyncExternalStoreWithSelector(
|
|
605
590
|
store.subscribe,
|
|
606
591
|
store.getSnapshot,
|
|
607
|
-
store.getSnapshot,
|
|
608
|
-
|
|
592
|
+
store.getServerSnapshot ?? store.getSnapshot,
|
|
593
|
+
selectorTopicEligible ? (snapshot) => snapshot : (snapshot) => actualSelector(snapshot),
|
|
609
594
|
actualEqualityFn
|
|
610
595
|
);
|
|
611
596
|
useEffect3(() => {
|
|
612
|
-
if (!isDevEnv() && !
|
|
597
|
+
if (!isDevEnv() && !Logix4.Debug.isDevtoolsEnabled()) {
|
|
613
598
|
return;
|
|
614
599
|
}
|
|
615
600
|
const instanceId = moduleRuntime.instanceId;
|
|
@@ -625,7 +610,7 @@ function useSelector(handle, selector, equalityFn) {
|
|
|
625
610
|
const rawDebugKey = meta.debugKey;
|
|
626
611
|
selectorKey = typeof rawDebugKey === "string" && rawDebugKey.length > 0 ? rawDebugKey : typeof selector.name === "string" && selector.name.length > 0 ? selector.name : void 0;
|
|
627
612
|
}
|
|
628
|
-
const effect =
|
|
613
|
+
const effect = Logix4.Debug.record({
|
|
629
614
|
type: "trace:react-selector",
|
|
630
615
|
moduleId: moduleRuntime.moduleId,
|
|
631
616
|
instanceId,
|
|
@@ -649,11 +634,11 @@ function useSelector(handle, selector, equalityFn) {
|
|
|
649
634
|
|
|
650
635
|
// src/internal/hooks/useModule.ts
|
|
651
636
|
import React2 from "react";
|
|
652
|
-
import * as
|
|
653
|
-
import {
|
|
637
|
+
import * as Logix6 from "@logixjs/core";
|
|
638
|
+
import { Effect as Effect4, Layer as Layer2, ServiceMap } from "effect";
|
|
654
639
|
|
|
655
640
|
// src/internal/store/resolveImportedModuleRef.ts
|
|
656
|
-
import * as
|
|
641
|
+
import * as Logix5 from "@logixjs/core";
|
|
657
642
|
var getOrCreateWeakMap = (map, key, make) => {
|
|
658
643
|
const cached = map.get(key);
|
|
659
644
|
if (cached) return cached;
|
|
@@ -677,7 +662,7 @@ var resolveImportedModuleRef = (runtime, parentRuntime, module) => {
|
|
|
677
662
|
if (cached) {
|
|
678
663
|
return cached;
|
|
679
664
|
}
|
|
680
|
-
const importsScope =
|
|
665
|
+
const importsScope = Logix5.InternalContracts.getImportsScope(parentRuntime);
|
|
681
666
|
const childRuntime = importsScope.get(module);
|
|
682
667
|
if (childRuntime) {
|
|
683
668
|
const dispatch = Object.assign(
|
|
@@ -763,8 +748,8 @@ var useStableId = () => {
|
|
|
763
748
|
|
|
764
749
|
// src/internal/hooks/useModule.ts
|
|
765
750
|
var isModuleImpl = (handle) => Boolean(handle) && typeof handle === "object" && handle._tag === "ModuleImpl";
|
|
766
|
-
var isModule = (handle) =>
|
|
767
|
-
var isModuleDef = (handle) =>
|
|
751
|
+
var isModule = (handle) => Logix6.Module.hasImpl(handle);
|
|
752
|
+
var isModuleDef = (handle) => Logix6.Module.is(handle) && handle._kind === "ModuleDef";
|
|
768
753
|
function useModule(handle, selectorOrOptions, equalityFn) {
|
|
769
754
|
const runtimeBase = useRuntime();
|
|
770
755
|
const runtimeContext = React2.useContext(RuntimeContext);
|
|
@@ -788,6 +773,7 @@ function useModule(handle, selectorOrOptions, equalityFn) {
|
|
|
788
773
|
}
|
|
789
774
|
}
|
|
790
775
|
let runtime;
|
|
776
|
+
const moduleImplResolveTraceRef = React2.useRef(void 0);
|
|
791
777
|
if (isModuleImpl(normalizedHandle)) {
|
|
792
778
|
const cache = React2.useMemo(
|
|
793
779
|
() => getModuleCache(runtimeBase, runtimeContext.reactConfigSnapshot, runtimeContext.configVersion),
|
|
@@ -816,9 +802,9 @@ function useModule(handle, selectorOrOptions, equalityFn) {
|
|
|
816
802
|
const key = depsHash ? `${baseKey}:${depsHash}` : baseKey;
|
|
817
803
|
const ownerId = moduleId;
|
|
818
804
|
const baseFactory = React2.useMemo(
|
|
819
|
-
() => (scope) => Layer2.buildWithScope(normalizedHandle.layer, scope).pipe(
|
|
805
|
+
() => (scope) => Layer2.buildWithScope(Layer2.fresh(normalizedHandle.layer), scope).pipe(
|
|
820
806
|
Effect4.map(
|
|
821
|
-
(context) =>
|
|
807
|
+
(context) => ServiceMap.get(context, normalizedHandle.module)
|
|
822
808
|
)
|
|
823
809
|
),
|
|
824
810
|
[normalizedHandle]
|
|
@@ -828,26 +814,56 @@ function useModule(handle, selectorOrOptions, equalityFn) {
|
|
|
828
814
|
return baseFactory;
|
|
829
815
|
}
|
|
830
816
|
return (scope) => baseFactory(scope).pipe(
|
|
831
|
-
Effect4.
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
817
|
+
Effect4.timeoutOption(initTimeoutMs),
|
|
818
|
+
Effect4.flatMap(
|
|
819
|
+
(maybe) => maybe._tag === "Some" ? Effect4.succeed(maybe.value) : Effect4.die(new Error(`[useModule] Module "${ownerId}" initialization timed out after ${initTimeoutMs}ms`))
|
|
820
|
+
)
|
|
835
821
|
);
|
|
836
822
|
}, [baseFactory, suspend, initTimeoutMs, ownerId]);
|
|
823
|
+
const moduleResolveStartedAt = performance.now();
|
|
837
824
|
const moduleRuntime = suspend ? cache.read(key, factory, gcTime, ownerId, {
|
|
838
825
|
entrypoint: "react.useModule",
|
|
839
826
|
policyMode: runtimeContext.policy.mode,
|
|
840
|
-
yield: runtimeContext.policy.yield
|
|
827
|
+
yield: runtimeContext.policy.yield,
|
|
828
|
+
optimisticSyncBudgetMs: runtimeContext.policy.syncBudgetMs
|
|
841
829
|
}) : cache.readSync(key, factory, gcTime, ownerId, {
|
|
842
830
|
entrypoint: "react.useModule",
|
|
843
831
|
policyMode: runtimeContext.policy.mode,
|
|
844
832
|
warnSyncBlockingThresholdMs: 5
|
|
845
833
|
});
|
|
834
|
+
moduleImplResolveTraceRef.current = {
|
|
835
|
+
moduleId,
|
|
836
|
+
cacheMode: suspend ? "suspend" : "sync",
|
|
837
|
+
durationMs: Math.round((performance.now() - moduleResolveStartedAt) * 100) / 100
|
|
838
|
+
};
|
|
846
839
|
React2.useEffect(() => cache.retain(key), [cache, key]);
|
|
847
840
|
runtime = moduleRuntime;
|
|
848
841
|
} else {
|
|
849
842
|
runtime = useModuleRuntime(normalizedHandle);
|
|
850
843
|
}
|
|
844
|
+
React2.useEffect(() => {
|
|
845
|
+
if (!isModuleImpl(normalizedHandle)) {
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const diagnosticsLevel = readRuntimeDiagnosticsLevel(runtimeBase);
|
|
849
|
+
if (diagnosticsLevel === "off") {
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
const trace = moduleImplResolveTraceRef.current;
|
|
853
|
+
if (!trace) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
const effect = Logix6.Debug.record({
|
|
857
|
+
type: "trace:react.moduleImpl.resolve",
|
|
858
|
+
moduleId: trace.moduleId,
|
|
859
|
+
instanceId: runtime.instanceId,
|
|
860
|
+
data: {
|
|
861
|
+
cacheMode: trace.cacheMode,
|
|
862
|
+
durationMs: trace.durationMs
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
emitRuntimeDebugEventBestEffort(runtimeBase, effect);
|
|
866
|
+
}, [runtimeBase, runtime, normalizedHandle]);
|
|
851
867
|
React2.useEffect(() => {
|
|
852
868
|
if (!isModuleImpl(normalizedHandle)) {
|
|
853
869
|
return;
|
|
@@ -857,22 +873,22 @@ function useModule(handle, selectorOrOptions, equalityFn) {
|
|
|
857
873
|
if (!label) {
|
|
858
874
|
return;
|
|
859
875
|
}
|
|
860
|
-
const effect =
|
|
876
|
+
const effect = Logix6.Debug.record({
|
|
861
877
|
type: "trace:instanceLabel",
|
|
862
878
|
moduleId: normalizedHandle.module.id,
|
|
863
879
|
instanceId: runtime.instanceId,
|
|
864
880
|
data: { label }
|
|
865
881
|
});
|
|
866
|
-
runtimeBase
|
|
882
|
+
emitRuntimeDebugEventBestEffort(runtimeBase, effect);
|
|
867
883
|
}, [runtimeBase, runtime, normalizedHandle, options]);
|
|
868
884
|
React2.useEffect(() => {
|
|
869
|
-
if (!isDevEnv() && !
|
|
885
|
+
if (!isDevEnv() && !Logix6.Debug.isDevtoolsEnabled()) {
|
|
870
886
|
return;
|
|
871
887
|
}
|
|
872
888
|
if (!runtime.instanceId) {
|
|
873
889
|
return;
|
|
874
890
|
}
|
|
875
|
-
const effect =
|
|
891
|
+
const effect = Logix6.Debug.record({
|
|
876
892
|
type: "trace:react-render",
|
|
877
893
|
moduleId: runtime.moduleId,
|
|
878
894
|
instanceId: runtime.instanceId,
|
|
@@ -882,7 +898,7 @@ function useModule(handle, selectorOrOptions, equalityFn) {
|
|
|
882
898
|
}
|
|
883
899
|
});
|
|
884
900
|
runtimeBase.runFork(effect);
|
|
885
|
-
}
|
|
901
|
+
});
|
|
886
902
|
if (selector) {
|
|
887
903
|
if (isModuleImpl(normalizedHandle)) {
|
|
888
904
|
return useSelector(runtime, selector, equalityFn);
|