wevu 7.3.0 → 7.5.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 +2 -0
- package/dist/dev/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/defineProperty.mjs +1 -1
- package/dist/dev/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/toPrimitive.mjs +1 -1
- package/dist/dev/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/toPropertyKey.mjs +1 -1
- package/dist/dev/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/typeof.mjs +1 -1
- package/dist/dev/package.mjs +1 -1
- package/dist/dev/reactivity/core.mjs +1 -1
- package/dist/dev/reactivity/ref.mjs +1 -1
- package/dist/dev/router/initialNavigation.mjs +4 -1
- package/dist/dev/router/initialNavigation.mjs.map +1 -1
- package/dist/dev/router/scrollRestoration/adapters.mjs +86 -0
- package/dist/dev/router/scrollRestoration/adapters.mjs.map +1 -0
- package/dist/dev/router/scrollRestoration/controller.mjs +148 -0
- package/dist/dev/router/scrollRestoration/controller.mjs.map +1 -0
- package/dist/dev/router/scrollRestoration/host.mjs +76 -0
- package/dist/dev/router/scrollRestoration/host.mjs.map +1 -0
- package/dist/dev/router/scrollRestoration/index.mjs +156 -0
- package/dist/dev/router/scrollRestoration/index.mjs.map +1 -0
- package/dist/dev/router.mjs +4 -1
- package/dist/dev/runtime/app/diagnostics.mjs +5 -1
- package/dist/dev/runtime/app/diagnostics.mjs.map +1 -1
- package/dist/dev/runtime/app/mount.mjs +8 -3
- package/dist/dev/runtime/app/mount.mjs.map +1 -1
- package/dist/dev/runtime/app/setData/commitTracker.mjs +39 -4
- package/dist/dev/runtime/app/setData/commitTracker.mjs.map +1 -1
- package/dist/dev/runtime/app/setData/observation.mjs +109 -0
- package/dist/dev/runtime/app/setData/observation.mjs.map +1 -0
- package/dist/dev/runtime/app/setData/scheduler.mjs +12 -1
- package/dist/dev/runtime/app/setData/scheduler.mjs.map +1 -1
- package/dist/dev/runtime/app/setDataOptions.mjs +1 -0
- package/dist/dev/runtime/app/setDataOptions.mjs.map +1 -1
- package/dist/dev/runtime/define/initialComputed.mjs +13 -12
- package/dist/dev/runtime/define/initialComputed.mjs.map +1 -1
- package/dist/dev/runtime/define/props.mjs +5 -1
- package/dist/dev/runtime/define/props.mjs.map +1 -1
- package/dist/dev/runtime/define/scopedSlotOptions.mjs +2 -1
- package/dist/dev/runtime/define/scopedSlotOptions.mjs.map +1 -1
- package/dist/dev/runtime/define.mjs +1 -1
- package/dist/dev/runtime/define.mjs.map +1 -1
- package/dist/dev/runtime/features/scopedSlots.mjs.map +1 -1
- package/dist/dev/runtime/hooks/base.mjs +1 -13
- package/dist/dev/runtime/hooks/base.mjs.map +1 -1
- package/dist/dev/runtime/hooks/pageScroll.mjs +41 -0
- package/dist/dev/runtime/hooks/pageScroll.mjs.map +1 -0
- package/dist/dev/runtime/hooks/register.mjs +2 -1
- package/dist/dev/runtime/hooks/register.mjs.map +1 -1
- package/dist/dev/runtime/register/component/lifecycle/optionalHooks.mjs +2 -5
- package/dist/dev/runtime/register/component/lifecycle/optionalHooks.mjs.map +1 -1
- package/dist/dev/runtime/register/component/lifecycle/platform.mjs +8 -20
- package/dist/dev/runtime/register/component/lifecycle/platform.mjs.map +1 -1
- package/dist/dev/runtime/register/component/props.mjs +14 -4
- package/dist/dev/runtime/register/component/props.mjs.map +1 -1
- package/dist/dev/runtime/register/component/registerDefinition.mjs +30 -17
- package/dist/dev/runtime/register/component/registerDefinition.mjs.map +1 -1
- package/dist/dev/runtime/register/component.mjs +2 -1
- package/dist/dev/runtime/register/component.mjs.map +1 -1
- package/dist/dev/runtime/register/runtimeInstance/methodBridge.mjs +14 -7
- package/dist/dev/runtime/register/runtimeInstance/methodBridge.mjs.map +1 -1
- package/dist/dev/runtime/register/runtimeInstance/nativeDeclaration.mjs +78 -0
- package/dist/dev/runtime/register/runtimeInstance/nativeDeclaration.mjs.map +1 -0
- package/dist/dev/runtime/register/runtimeInstance/provideContext.mjs +52 -8
- package/dist/dev/runtime/register/runtimeInstance/provideContext.mjs.map +1 -1
- package/dist/dev/runtime/register/runtimeInstance/setupPhase.mjs +7 -2
- package/dist/dev/runtime/register/runtimeInstance/setupPhase.mjs.map +1 -1
- package/dist/dev/runtime/register/runtimeInstance/utils.mjs.map +1 -1
- package/dist/dev/runtime/register/runtimeInstance.mjs +60 -19
- package/dist/dev/runtime/register/runtimeInstance.mjs.map +1 -1
- package/dist/fetch.mjs +1 -1
- package/dist/internal-template.mjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/reactivity/core.mjs +1 -1
- package/dist/reactivity/reactive/patch.mjs +1 -1
- package/dist/reactivity/reactive/patchState.mjs +1 -1
- package/dist/reactivity/ref.mjs +1 -1
- package/dist/reactivity/watch/helpers.mjs +1 -1
- package/dist/router/initialNavigation.mjs +1 -1
- package/dist/router/scrollRestoration/adapters.d.mts +7 -0
- package/dist/router/scrollRestoration/adapters.mjs +1 -0
- package/dist/router/scrollRestoration/controller.d.mts +7 -0
- package/dist/router/scrollRestoration/controller.mjs +1 -0
- package/dist/router/scrollRestoration/host.d.mts +3 -0
- package/dist/router/scrollRestoration/host.mjs +1 -0
- package/dist/router/scrollRestoration/index.d.mts +8 -0
- package/dist/router/scrollRestoration/index.mjs +1 -0
- package/dist/router/scrollRestoration/types.d.mts +60 -0
- package/dist/router/useRoute.mjs +1 -1
- package/dist/router.d.mts +5 -1
- package/dist/router.mjs +1 -1
- package/dist/routerInternal/matching.mjs +1 -1
- package/dist/routerInternal/params.mjs +1 -1
- package/dist/routerInternal/path.mjs +1 -1
- package/dist/routerInternal/query.mjs +1 -1
- package/dist/routerInternal/records.mjs +1 -1
- package/dist/runtime/app/context.mjs +1 -1
- package/dist/runtime/app/diagnostics.mjs +1 -1
- package/dist/runtime/app/mount.mjs +1 -1
- package/dist/runtime/app/setData/commitTracker.d.mts +2 -1
- package/dist/runtime/app/setData/commitTracker.mjs +1 -1
- package/dist/runtime/app/setData/observation.d.mts +12 -0
- package/dist/runtime/app/setData/observation.mjs +1 -0
- package/dist/runtime/app/setData/scheduler.d.mts +1 -0
- package/dist/runtime/app/setData/scheduler.mjs +1 -1
- package/dist/runtime/app/setDataOptions.mjs +1 -1
- package/dist/runtime/define/initialComputed.mjs +1 -1
- package/dist/runtime/define/props.mjs +1 -1
- package/dist/runtime/define/scopedSlotOptions.mjs +1 -1
- package/dist/runtime/define.mjs +1 -1
- package/dist/runtime/diff.mjs +1 -1
- package/dist/runtime/features/publicLayout.mjs +1 -1
- package/dist/runtime/features/scopedSlots.d.mts +2 -1
- package/dist/runtime/hooks/base.mjs +1 -1
- package/dist/runtime/hooks/pageScroll.mjs +1 -0
- package/dist/runtime/hooks/register.mjs +1 -1
- package/dist/runtime/jsxIsland.mjs +1 -1
- package/dist/runtime/pageLayout.mjs +1 -1
- package/dist/runtime/pageScroll.mjs +1 -1
- package/dist/runtime/register/component/alipayRegistration.mjs +1 -1
- package/dist/runtime/register/component/lifecycle/optionalHooks.mjs +1 -1
- package/dist/runtime/register/component/lifecycle/platform.mjs +1 -1
- package/dist/runtime/register/component/lifecycle.mjs +1 -1
- package/dist/runtime/register/component/props.mjs +1 -1
- package/dist/runtime/register/component/registerDefinition.mjs +1 -1
- package/dist/runtime/register/component/registerNativeDefinition.mjs +1 -1
- package/dist/runtime/register/component.mjs +1 -1
- package/dist/runtime/register/runtimeInstance/methodBridge.mjs +1 -1
- package/dist/runtime/register/runtimeInstance/nativeDeclaration.mjs +1 -0
- package/dist/runtime/register/runtimeInstance/provideContext.mjs +1 -1
- package/dist/runtime/register/runtimeInstance/setupPhase.mjs +1 -1
- package/dist/runtime/register/runtimeInstance.d.mts +8 -4
- package/dist/runtime/register/runtimeInstance.mjs +1 -1
- package/dist/runtime/setupTracking.mjs +1 -1
- package/dist/runtime/templateRefs.mjs +1 -1
- package/dist/runtime/types/runtime.d.mts +1 -0
- package/dist/runtime/types/setData.d.mts +30 -0
- package/dist/scheduler.mjs +1 -1
- package/dist/web-apis.mjs +1 -1
- package/package.json +10 -9
- package/dist/dev/api/vitest/setup.d.mts +0 -1
- package/dist/dev/api/vitest.d.mts +0 -1
- package/dist/dev/api.d.mts +0 -1
- package/dist/dev/compiler.d.mts +0 -1
- package/dist/dev/fetch.d.mts +0 -9
- package/dist/dev/index.d.mts +0 -72
- package/dist/dev/internal-reactivity.d.mts +0 -18
- package/dist/dev/internal-runtime.d.mts +0 -45
- package/dist/dev/internal-template.d.mts +0 -2
- package/dist/dev/jsxTypes.d.mts +0 -9
- package/dist/dev/macros/shared.d.mts +0 -83
- package/dist/dev/macros.d.mts +0 -71
- package/dist/dev/reactivity/asyncDerivation.d.mts +0 -41
- package/dist/dev/reactivity/computed.d.mts +0 -25
- package/dist/dev/reactivity/core.d.mts +0 -35
- package/dist/dev/reactivity/index.d.mts +0 -16
- package/dist/dev/reactivity/reactive/mutation.d.mts +0 -21
- package/dist/dev/reactivity/reactive/patch.d.mts +0 -18
- package/dist/dev/reactivity/reactive/shallow.d.mts +0 -22
- package/dist/dev/reactivity/reactive/shared.d.mts +0 -4
- package/dist/dev/reactivity/reactive.d.mts +0 -42
- package/dist/dev/reactivity/readonly.d.mts +0 -27
- package/dist/dev/reactivity/ref.d.mts +0 -27
- package/dist/dev/reactivity/shallowRef.d.mts +0 -19
- package/dist/dev/reactivity/toRefs.d.mts +0 -43
- package/dist/dev/reactivity/traverse.d.mts +0 -8
- package/dist/dev/reactivity/watch/types.d.mts +0 -43
- package/dist/dev/reactivity/watch.d.mts +0 -22
- package/dist/dev/router/auto-routes.d.mts +0 -8
- package/dist/dev/router/createRouter.d.mts +0 -9
- package/dist/dev/router/navigationCore.d.mts +0 -7
- package/dist/dev/router/resolve.d.mts +0 -7
- package/dist/dev/router/routeSync.d.mts +0 -2
- package/dist/dev/router/types.d.mts +0 -267
- package/dist/dev/router/useRoute.d.mts +0 -20
- package/dist/dev/router/useRouter.d.mts +0 -9
- package/dist/dev/router.d.mts +0 -26
- package/dist/dev/routerInternal/location.d.mts +0 -2
- package/dist/dev/routerInternal/matching.d.mts +0 -2
- package/dist/dev/routerInternal/params.d.mts +0 -2
- package/dist/dev/routerInternal/query.d.mts +0 -7
- package/dist/dev/routerInternal/records.d.mts +0 -2
- package/dist/dev/routerInternal/recordsWarnings.d.mts +0 -2
- package/dist/dev/routerInternal/shared.d.mts +0 -9
- package/dist/dev/routerInternal/snapshots.d.mts +0 -2
- package/dist/dev/routerInternal/types.d.mts +0 -9
- package/dist/dev/runtime/app/pending.d.mts +0 -10
- package/dist/dev/runtime/app/setData/commitTracker.d.mts +0 -13
- package/dist/dev/runtime/app/setData/scheduler.d.mts +0 -51
- package/dist/dev/runtime/app.d.mts +0 -8
- package/dist/dev/runtime/capabilities.d.mts +0 -78
- package/dist/dev/runtime/css.d.mts +0 -14
- package/dist/dev/runtime/defaults.d.mts +0 -12
- package/dist/dev/runtime/define.d.mts +0 -118
- package/dist/dev/runtime/disposables.d.mts +0 -31
- package/dist/dev/runtime/elementIntersectionObserver.d.mts +0 -26
- package/dist/dev/runtime/features/inlineEvents.d.mts +0 -7
- package/dist/dev/runtime/features/jsxIslands.d.mts +0 -7
- package/dist/dev/runtime/features/layout.d.mts +0 -7
- package/dist/dev/runtime/features/patchStrategy.d.mts +0 -7
- package/dist/dev/runtime/features/publicLayout.d.mts +0 -24
- package/dist/dev/runtime/features/scopedSlots.d.mts +0 -23
- package/dist/dev/runtime/features/setDataHighFrequencyWarning.d.mts +0 -7
- package/dist/dev/runtime/features/templateRefs.d.mts +0 -7
- package/dist/dev/runtime/hooks/base.d.mts +0 -27
- package/dist/dev/runtime/hooks/register.d.mts +0 -30
- package/dist/dev/runtime/hooks/vue.d.mts +0 -52
- package/dist/dev/runtime/hooks.d.mts +0 -4
- package/dist/dev/runtime/index.d.mts +0 -46
- package/dist/dev/runtime/intersectionObserver.d.mts +0 -14
- package/dist/dev/runtime/jsxIsland.d.mts +0 -37
- package/dist/dev/runtime/layoutBridge.d.mts +0 -55
- package/dist/dev/runtime/noSetData.d.mts +0 -5
- package/dist/dev/runtime/pageEnvironment.d.mts +0 -50
- package/dist/dev/runtime/pageLayout.d.mts +0 -25
- package/dist/dev/runtime/pageScroll.d.mts +0 -29
- package/dist/dev/runtime/provide.d.mts +0 -60
- package/dist/dev/runtime/provideStore.d.mts +0 -7
- package/dist/dev/runtime/publicRuntime.d.mts +0 -22
- package/dist/dev/runtime/pullDownRefresh.d.mts +0 -12
- package/dist/dev/runtime/register/app.d.mts +0 -14
- package/dist/dev/runtime/register/component.d.mts +0 -17
- package/dist/dev/runtime/register/inline.d.mts +0 -15
- package/dist/dev/runtime/register/runtimeInstance.d.mts +0 -26
- package/dist/dev/runtime/register/setup.d.mts +0 -11
- package/dist/dev/runtime/register/watch.d.mts +0 -12
- package/dist/dev/runtime/register.d.mts +0 -5
- package/dist/dev/runtime/selectorQuery.d.mts +0 -54
- package/dist/dev/runtime/template.d.mts +0 -6
- package/dist/dev/runtime/templateRefTypes.d.mts +0 -12
- package/dist/dev/runtime/types/core.d.mts +0 -35
- package/dist/dev/runtime/types/miniprogram.d.mts +0 -84
- package/dist/dev/runtime/types/miniprogramHost.d.mts +0 -45
- package/dist/dev/runtime/types/miniprogramHostSources.d.mts +0 -112
- package/dist/dev/runtime/types/options.d.mts +0 -138
- package/dist/dev/runtime/types/props/propTypes.d.mts +0 -79
- package/dist/dev/runtime/types/props/router.d.mts +0 -51
- package/dist/dev/runtime/types/props/setup.d.mts +0 -96
- package/dist/dev/runtime/types/props.d.mts +0 -4
- package/dist/dev/runtime/types/runtime.d.mts +0 -59
- package/dist/dev/runtime/types/setData.d.mts +0 -237
- package/dist/dev/runtime/types.d.mts +0 -29
- package/dist/dev/runtime/uniAppHost.d.mts +0 -8
- package/dist/dev/runtime/updatePerformance.d.mts +0 -13
- package/dist/dev/runtime/use.d.mts +0 -13
- package/dist/dev/runtime/vueCompat/context.d.mts +0 -8
- package/dist/dev/runtime/vueCompat/model.d.mts +0 -30
- package/dist/dev/runtime/vueCompat/router.d.mts +0 -29
- package/dist/dev/runtime/vueCompat/templateRef.d.mts +0 -9
- package/dist/dev/runtime/vueCompat.d.mts +0 -5
- package/dist/dev/scheduler.d.mts +0 -4
- package/dist/dev/store/define.d.mts +0 -8
- package/dist/dev/store/manager.d.mts +0 -16
- package/dist/dev/store/storeToRefs.d.mts +0 -11
- package/dist/dev/store/types.d.mts +0 -106
- package/dist/dev/store.d.mts +0 -5
- package/dist/dev/version.d.mts +0 -4
- package/dist/dev/vue-augment.d.mts +0 -8
- package/dist/dev/vue-demi.d.mts +0 -87
- package/dist/dev/vue-types.d.mts +0 -19
- package/dist/dev/web-apis.d.mts +0 -3
- /package/dist/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/defineProperty.mjs +0 -0
- /package/dist/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/toPrimitive.mjs +0 -0
- /package/dist/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/toPropertyKey.mjs +0 -0
- /package/dist/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.153.0}/helpers/esm/typeof.mjs +0 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { onScopeDispose } from "../../reactivity/core.mjs";
|
|
2
|
+
import { assertInSetup, getCurrentSetupContext } from "../../runtime/hooks/base.mjs";
|
|
3
|
+
import { getInitialNavigationPromise } from "../initialNavigation.mjs";
|
|
4
|
+
import { addScrollHook, currentScrollPage, resolveScrollPage } from "./host.mjs";
|
|
5
|
+
import { createScrollRestoration, resolveScrollController } from "./controller.mjs";
|
|
6
|
+
import { WEVU_READY_CALLED_KEY } from "@weapp-core/constants";
|
|
7
|
+
|
|
8
|
+
//#region src/router/scrollRestoration/index.ts
|
|
9
|
+
function getScrollSetupScope() {
|
|
10
|
+
const instance = assertInSetup("useScrollRestoration");
|
|
11
|
+
const proxy = getCurrentSetupContext()?.proxy;
|
|
12
|
+
if (typeof proxy?.$nextTick !== "function") throw new TypeError("scroll restoration 需要具有宿主提交屏障的 wevu setup 实例。");
|
|
13
|
+
return {
|
|
14
|
+
instance,
|
|
15
|
+
commit: () => proxy.$nextTick()
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function registerScrollRestoration(options, lifecycle) {
|
|
19
|
+
const { instance, commit } = getScrollSetupScope();
|
|
20
|
+
const state = resolveScrollController(options.controller);
|
|
21
|
+
const cleanups = [];
|
|
22
|
+
let page;
|
|
23
|
+
let route;
|
|
24
|
+
let stopped = false;
|
|
25
|
+
let visible = true;
|
|
26
|
+
let captured = false;
|
|
27
|
+
let attempted = false;
|
|
28
|
+
let request = 0;
|
|
29
|
+
let instanceReady = Boolean(instance[WEVU_READY_CALLED_KEY]);
|
|
30
|
+
let pageReady = false;
|
|
31
|
+
let readyPromise;
|
|
32
|
+
let resolveReady;
|
|
33
|
+
let registration;
|
|
34
|
+
function releaseReady() {
|
|
35
|
+
if (stopped || instanceReady && pageReady) resolveReady?.();
|
|
36
|
+
}
|
|
37
|
+
function bindPage() {
|
|
38
|
+
if (page || stopped) return;
|
|
39
|
+
const owner = resolveScrollPage(instance);
|
|
40
|
+
if (!owner) return;
|
|
41
|
+
const nextRoute = state.resolveRoute(owner);
|
|
42
|
+
registration.key = typeof options.key === "function" ? options.key(nextRoute) : options.key ?? nextRoute.fullPath;
|
|
43
|
+
const unregister = state.register(owner, registration);
|
|
44
|
+
page = owner;
|
|
45
|
+
route = nextRoute;
|
|
46
|
+
cleanups.push(unregister);
|
|
47
|
+
pageReady = Boolean(owner[WEVU_READY_CALLED_KEY]);
|
|
48
|
+
cleanups.push(addScrollHook(owner, "onReady", () => {
|
|
49
|
+
pageReady = true;
|
|
50
|
+
releaseReady();
|
|
51
|
+
registration.restoreAutomatic();
|
|
52
|
+
}));
|
|
53
|
+
lifecycle?.onBindPage?.(owner);
|
|
54
|
+
}
|
|
55
|
+
async function scroll() {
|
|
56
|
+
if (stopped || state.disposed) return false;
|
|
57
|
+
bindPage();
|
|
58
|
+
if (!page || !route) throw new Error("无法确定 scroll restoration 的原生归属页面,请在页面 attached 后恢复。");
|
|
59
|
+
if (!visible || currentScrollPage() !== page) return false;
|
|
60
|
+
const ticket = ++request;
|
|
61
|
+
const generation = state.generation;
|
|
62
|
+
const context = {
|
|
63
|
+
route,
|
|
64
|
+
routeEventId: state.transition?.page === page ? state.transition.event.routeEventId : void 0,
|
|
65
|
+
isActive: () => !stopped && !state.disposed && visible && ticket === request && generation === state.generation && currentScrollPage() === page
|
|
66
|
+
};
|
|
67
|
+
if (!instanceReady || !pageReady) {
|
|
68
|
+
readyPromise ?? (readyPromise = new Promise((resolve) => {
|
|
69
|
+
resolveReady = resolve;
|
|
70
|
+
}));
|
|
71
|
+
await readyPromise;
|
|
72
|
+
}
|
|
73
|
+
if (!context.isActive()) return false;
|
|
74
|
+
if (await getInitialNavigationPromise(page) === false || !context.isActive()) return false;
|
|
75
|
+
await commit();
|
|
76
|
+
if (!context.isActive()) return false;
|
|
77
|
+
const snapshot = state.read(registration.key, registration.id);
|
|
78
|
+
await options.restore(snapshot, context);
|
|
79
|
+
return context.isActive();
|
|
80
|
+
}
|
|
81
|
+
registration = {
|
|
82
|
+
key: "",
|
|
83
|
+
id: options.id ?? "default",
|
|
84
|
+
capture() {
|
|
85
|
+
if (stopped || state.disposed || !page || !visible || captured) return;
|
|
86
|
+
captured = true;
|
|
87
|
+
try {
|
|
88
|
+
const snapshot = options.capture();
|
|
89
|
+
if (snapshot !== null && "then" in snapshot && typeof snapshot.then === "function") throw new TypeError("scroll restoration capture 必须同步返回快照,不能返回 Promise。");
|
|
90
|
+
state.save(registration.key, registration.id, snapshot);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
state.clear(registration.key, registration.id);
|
|
93
|
+
state.report(error);
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
invalidate() {
|
|
97
|
+
request++;
|
|
98
|
+
resolveReady?.();
|
|
99
|
+
readyPromise = void 0;
|
|
100
|
+
resolveReady = void 0;
|
|
101
|
+
},
|
|
102
|
+
restoreAutomatic() {
|
|
103
|
+
const transition = state.transition;
|
|
104
|
+
if (stopped || options.manual || attempted || !instanceReady || !pageReady || !transition?.fresh || !transition.done || transition.page !== page) return;
|
|
105
|
+
attempted = true;
|
|
106
|
+
scroll().catch(state.report);
|
|
107
|
+
},
|
|
108
|
+
stop() {
|
|
109
|
+
if (stopped) return;
|
|
110
|
+
stopped = true;
|
|
111
|
+
request++;
|
|
112
|
+
releaseReady();
|
|
113
|
+
for (const cleanup of cleanups) cleanup();
|
|
114
|
+
cleanups.length = 0;
|
|
115
|
+
lifecycle?.onStop?.();
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
function captureBeforeStop() {
|
|
119
|
+
registration.capture();
|
|
120
|
+
registration.stop();
|
|
121
|
+
}
|
|
122
|
+
cleanups.push(addScrollHook(instance, "onAttached", bindPage), addScrollHook(instance, "onReady", () => {
|
|
123
|
+
bindPage();
|
|
124
|
+
instanceReady = true;
|
|
125
|
+
releaseReady();
|
|
126
|
+
registration.restoreAutomatic();
|
|
127
|
+
}), addScrollHook(instance, "onShow", () => {
|
|
128
|
+
bindPage();
|
|
129
|
+
visible = true;
|
|
130
|
+
captured = false;
|
|
131
|
+
}), addScrollHook(instance, "onHide", () => {
|
|
132
|
+
registration.capture();
|
|
133
|
+
visible = false;
|
|
134
|
+
registration.invalidate();
|
|
135
|
+
}), addScrollHook(instance, "onDetached", captureBeforeStop), addScrollHook(instance, "onUnload", captureBeforeStop));
|
|
136
|
+
onScopeDispose(captureBeforeStop);
|
|
137
|
+
bindPage();
|
|
138
|
+
registration.restoreAutomatic();
|
|
139
|
+
return {
|
|
140
|
+
automatic: state.controller.automatic && !options.manual,
|
|
141
|
+
scroll,
|
|
142
|
+
clear: () => {
|
|
143
|
+
bindPage();
|
|
144
|
+
if (page) state.clear(registration.key, registration.id);
|
|
145
|
+
},
|
|
146
|
+
stop: registration.stop
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** 在同步 setup 中注册快照;只恢复新实例,不覆盖原生保留页的位置。 */
|
|
150
|
+
function useScrollRestoration(options) {
|
|
151
|
+
return registerScrollRestoration(options);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
//#endregion
|
|
155
|
+
export { createScrollRestoration, getScrollSetupScope, registerScrollRestoration, useScrollRestoration };
|
|
156
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/router/scrollRestoration/index.ts"],"sourcesContent":["import type { ScrollRegistration } from './controller'\nimport type { ScrollPage } from './host'\nimport type { ScrollRestorationContext, ScrollRestorationHandle, UseScrollRestorationOptions } from './types'\nimport { WEVU_READY_CALLED_KEY } from '@weapp-core/constants'\nimport { onScopeDispose } from '../../reactivity'\nimport { assertInSetup, getCurrentSetupContext } from '../../runtime/hooks/base'\nimport { getInitialNavigationPromise } from '../initialNavigation'\nimport { resolveScrollController } from './controller'\nimport { addScrollHook, currentScrollPage, resolveScrollPage } from './host'\n\nexport { createScrollRestoration } from './controller'\nexport type * from './types'\n\nexport function getScrollSetupScope() {\n const instance: ScrollPage = assertInSetup('useScrollRestoration')\n const proxy = getCurrentSetupContext<{ proxy: { $nextTick: () => Promise<void> } }>()?.proxy\n if (typeof proxy?.$nextTick !== 'function') {\n throw new TypeError('scroll restoration 需要具有宿主提交屏障的 wevu setup 实例。')\n }\n return { instance, commit: () => proxy.$nextTick() }\n}\n\nexport function registerScrollRestoration<T extends object>(\n options: UseScrollRestorationOptions<T>,\n lifecycle?: { onBindPage?: (page: ScrollPage) => void, onStop?: () => void },\n): ScrollRestorationHandle {\n const { instance, commit } = getScrollSetupScope()\n const state = resolveScrollController(options.controller)\n const cleanups: Array<() => void> = []\n let page: ScrollPage | undefined\n let route: ScrollRestorationContext['route'] | undefined\n let stopped = false\n let visible = true\n let captured = false\n let attempted = false\n let request = 0\n let instanceReady = Boolean(instance[WEVU_READY_CALLED_KEY])\n let pageReady = false\n let readyPromise: Promise<void> | undefined\n let resolveReady: (() => void) | undefined\n let registration: ScrollRegistration\n\n function releaseReady() {\n if (stopped || (instanceReady && pageReady)) {\n resolveReady?.()\n }\n }\n\n function bindPage() {\n if (page || stopped) {\n return\n }\n const owner = resolveScrollPage(instance)\n if (!owner) {\n return\n }\n const nextRoute = state.resolveRoute(owner)\n registration.key = typeof options.key === 'function' ? options.key(nextRoute) : options.key ?? nextRoute.fullPath\n const unregister = state.register(owner, registration)\n page = owner\n route = nextRoute\n cleanups.push(unregister)\n pageReady = Boolean(owner[WEVU_READY_CALLED_KEY])\n cleanups.push(addScrollHook(owner, 'onReady', () => {\n pageReady = true\n releaseReady()\n registration.restoreAutomatic()\n }))\n lifecycle?.onBindPage?.(owner)\n }\n\n async function scroll(): Promise<boolean> {\n if (stopped || state.disposed) {\n return false\n }\n bindPage()\n if (!page || !route) {\n throw new Error('无法确定 scroll restoration 的原生归属页面,请在页面 attached 后恢复。')\n }\n if (!visible || currentScrollPage() !== page) {\n return false\n }\n const ticket = ++request\n const generation = state.generation\n const context: ScrollRestorationContext = {\n route,\n routeEventId: state.transition?.page === page ? state.transition.event.routeEventId : undefined,\n isActive: () => !stopped && !state.disposed && visible && ticket === request\n && generation === state.generation && currentScrollPage() === page,\n }\n if (!instanceReady || !pageReady) {\n readyPromise ??= new Promise<void>((resolve) => {\n resolveReady = resolve\n })\n await readyPromise\n }\n if (!context.isActive()) {\n return false\n }\n const shouldMount = await getInitialNavigationPromise(page)\n if (shouldMount === false || !context.isActive()) {\n return false\n }\n await commit()\n if (!context.isActive()) {\n return false\n }\n // 同一个 key/id 的注册共享快照格式;格式由使用者的 T 契约约束。\n const snapshot = state.read(registration.key, registration.id) as T | undefined\n await options.restore(snapshot, context)\n return context.isActive()\n }\n\n registration = {\n key: '',\n id: options.id ?? 'default',\n capture() {\n if (stopped || state.disposed || !page || !visible || captured) {\n return\n }\n captured = true\n try {\n const snapshot = options.capture()\n if (snapshot !== null && 'then' in snapshot && typeof snapshot.then === 'function') {\n throw new TypeError('scroll restoration capture 必须同步返回快照,不能返回 Promise。')\n }\n state.save(registration.key, registration.id, snapshot)\n }\n catch (error) {\n state.clear(registration.key, registration.id)\n state.report(error)\n }\n },\n invalidate() {\n request++\n resolveReady?.()\n readyPromise = undefined\n resolveReady = undefined\n },\n restoreAutomatic() {\n const transition = state.transition\n if (stopped || options.manual || attempted || !instanceReady || !pageReady\n || !transition?.fresh || !transition.done || transition.page !== page) {\n return\n }\n attempted = true\n void scroll().catch(state.report)\n },\n stop() {\n if (stopped) {\n return\n }\n stopped = true\n request++\n releaseReady()\n for (const cleanup of cleanups) {\n cleanup()\n }\n cleanups.length = 0\n lifecycle?.onStop?.()\n },\n }\n\n function captureBeforeStop() {\n // 生命周期销毁保留最后快照;显式 stop 只注销,不能撤销先前的 clear。\n registration.capture()\n registration.stop()\n }\n\n cleanups.push(\n addScrollHook(instance, 'onAttached', bindPage),\n addScrollHook(instance, 'onReady', () => {\n bindPage()\n instanceReady = true\n releaseReady()\n registration.restoreAutomatic()\n }),\n addScrollHook(instance, 'onShow', () => {\n bindPage()\n visible = true\n captured = false\n }),\n addScrollHook(instance, 'onHide', () => {\n registration.capture()\n visible = false\n registration.invalidate()\n }),\n addScrollHook(instance, 'onDetached', captureBeforeStop),\n addScrollHook(instance, 'onUnload', captureBeforeStop),\n )\n onScopeDispose(captureBeforeStop)\n bindPage()\n registration.restoreAutomatic()\n return {\n automatic: state.controller.automatic && !options.manual,\n scroll,\n clear: () => {\n bindPage()\n if (page) {\n state.clear(registration.key, registration.id)\n }\n },\n stop: registration.stop,\n }\n}\n\n/** 在同步 setup 中注册快照;只恢复新实例,不覆盖原生保留页的位置。 */\nexport function useScrollRestoration<T extends object>(options: UseScrollRestorationOptions<T>): ScrollRestorationHandle {\n return registerScrollRestoration(options)\n}\n"],"mappings":";;;;;;;;AAaA,SAAgB,sBAAsB;CACpC,MAAM,WAAuB,cAAc,sBAAsB;CACjE,MAAM,QAAQ,uBAAsE,CAAC,EAAE;CACvF,IAAI,OAAO,OAAO,cAAc,YAC9B,MAAM,IAAI,UAAU,+CAA+C;CAErE,OAAO;EAAE;EAAU,cAAc,MAAM,UAAU;CAAE;AACrD;AAEA,SAAgB,0BACd,SACA,WACyB;CACzB,MAAM,EAAE,UAAU,WAAW,oBAAoB;CACjD,MAAM,QAAQ,wBAAwB,QAAQ,UAAU;CACxD,MAAM,WAA8B,CAAC;CACrC,IAAI;CACJ,IAAI;CACJ,IAAI,UAAU;CACd,IAAI,UAAU;CACd,IAAI,WAAW;CACf,IAAI,YAAY;CAChB,IAAI,UAAU;CACd,IAAI,gBAAgB,QAAQ,SAAS,sBAAsB;CAC3D,IAAI,YAAY;CAChB,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,SAAS,eAAe;EACtB,IAAI,WAAY,iBAAiB,WAC/B,eAAe;CAEnB;CAEA,SAAS,WAAW;EAClB,IAAI,QAAQ,SACV;EAEF,MAAM,QAAQ,kBAAkB,QAAQ;EACxC,IAAI,CAAC,OACH;EAEF,MAAM,YAAY,MAAM,aAAa,KAAK;EAC1C,aAAa,MAAM,OAAO,QAAQ,QAAQ,aAAa,QAAQ,IAAI,SAAS,IAAI,QAAQ,OAAO,UAAU;EACzG,MAAM,aAAa,MAAM,SAAS,OAAO,YAAY;EACrD,OAAO;EACP,QAAQ;EACR,SAAS,KAAK,UAAU;EACxB,YAAY,QAAQ,MAAM,sBAAsB;EAChD,SAAS,KAAK,cAAc,OAAO,iBAAiB;GAClD,YAAY;GACZ,aAAa;GACb,aAAa,iBAAiB;EAChC,CAAC,CAAC;EACF,WAAW,aAAa,KAAK;CAC/B;CAEA,eAAe,SAA2B;EACxC,IAAI,WAAW,MAAM,UACnB,OAAO;EAET,SAAS;EACT,IAAI,CAAC,QAAQ,CAAC,OACZ,MAAM,IAAI,MAAM,oDAAoD;EAEtE,IAAI,CAAC,WAAW,kBAAkB,MAAM,MACtC,OAAO;EAET,MAAM,SAAS,EAAE;EACjB,MAAM,aAAa,MAAM;EACzB,MAAM,UAAoC;GACxC;GACA,cAAc,MAAM,YAAY,SAAS,OAAO,MAAM,WAAW,MAAM,eAAe;GACtF,gBAAgB,CAAC,WAAW,CAAC,MAAM,YAAY,WAAW,WAAW,WAChE,eAAe,MAAM,cAAc,kBAAkB,MAAM;EAClE;EACA,IAAI,CAAC,iBAAiB,CAAC,WAAW;GAChC,gCAAiB,IAAI,SAAe,YAAY;IAC9C,eAAe;GACjB,CAAC;GACD,MAAM;EACR;EACA,IAAI,CAAC,QAAQ,SAAS,GACpB,OAAO;EAGT,IAAI,MADsB,4BAA4B,IAAI,MACtC,SAAS,CAAC,QAAQ,SAAS,GAC7C,OAAO;EAET,MAAM,OAAO;EACb,IAAI,CAAC,QAAQ,SAAS,GACpB,OAAO;EAGT,MAAM,WAAW,MAAM,KAAK,aAAa,KAAK,aAAa,EAAE;EAC7D,MAAM,QAAQ,QAAQ,UAAU,OAAO;EACvC,OAAO,QAAQ,SAAS;CAC1B;CAEA,eAAe;EACb,KAAK;EACL,IAAI,QAAQ,MAAM;EAClB,UAAU;GACR,IAAI,WAAW,MAAM,YAAY,CAAC,QAAQ,CAAC,WAAW,UACpD;GAEF,WAAW;GACX,IAAI;IACF,MAAM,WAAW,QAAQ,QAAQ;IACjC,IAAI,aAAa,QAAQ,UAAU,YAAY,OAAO,SAAS,SAAS,YACtE,MAAM,IAAI,UAAU,mDAAmD;IAEzE,MAAM,KAAK,aAAa,KAAK,aAAa,IAAI,QAAQ;GACxD,SACO,OAAO;IACZ,MAAM,MAAM,aAAa,KAAK,aAAa,EAAE;IAC7C,MAAM,OAAO,KAAK;GACpB;EACF;EACA,aAAa;GACX;GACA,eAAe;GACf,eAAe;GACf,eAAe;EACjB;EACA,mBAAmB;GACjB,MAAM,aAAa,MAAM;GACzB,IAAI,WAAW,QAAQ,UAAU,aAAa,CAAC,iBAAiB,CAAC,aAC5D,CAAC,YAAY,SAAS,CAAC,WAAW,QAAQ,WAAW,SAAS,MACjE;GAEF,YAAY;GACZ,AAAK,OAAO,CAAC,CAAC,MAAM,MAAM,MAAM;EAClC;EACA,OAAO;GACL,IAAI,SACF;GAEF,UAAU;GACV;GACA,aAAa;GACb,KAAK,MAAM,WAAW,UACpB,QAAQ;GAEV,SAAS,SAAS;GAClB,WAAW,SAAS;EACtB;CACF;CAEA,SAAS,oBAAoB;EAE3B,aAAa,QAAQ;EACrB,aAAa,KAAK;CACpB;CAEA,SAAS,KACP,cAAc,UAAU,cAAc,QAAQ,GAC9C,cAAc,UAAU,iBAAiB;EACvC,SAAS;EACT,gBAAgB;EAChB,aAAa;EACb,aAAa,iBAAiB;CAChC,CAAC,GACD,cAAc,UAAU,gBAAgB;EACtC,SAAS;EACT,UAAU;EACV,WAAW;CACb,CAAC,GACD,cAAc,UAAU,gBAAgB;EACtC,aAAa,QAAQ;EACrB,UAAU;EACV,aAAa,WAAW;CAC1B,CAAC,GACD,cAAc,UAAU,cAAc,iBAAiB,GACvD,cAAc,UAAU,YAAY,iBAAiB,CACvD;CACA,eAAe,iBAAiB;CAChC,SAAS;CACT,aAAa,iBAAiB;CAC9B,OAAO;EACL,WAAW,MAAM,WAAW,aAAa,CAAC,QAAQ;EAClD;EACA,aAAa;GACX,SAAS;GACT,IAAI,MACF,MAAM,MAAM,aAAa,KAAK,aAAa,EAAE;EAEjD;EACA,MAAM,aAAa;CACrB;AACF;;AAGA,SAAgB,qBAAuC,SAAkE;CACvH,OAAO,0BAA0B,OAAO;AAC1C"}
|
package/dist/dev/router.mjs
CHANGED
|
@@ -4,6 +4,9 @@ import { createNavigationFailure, isNavigationFailure } from "./router/navigatio
|
|
|
4
4
|
import { resolveRouteLocation } from "./router/resolve.mjs";
|
|
5
5
|
import { useNativePageRouter, useNativeRouter, useRoute } from "./router/useRoute.mjs";
|
|
6
6
|
import { createRouter } from "./router/createRouter.mjs";
|
|
7
|
+
import { createScrollRestoration } from "./router/scrollRestoration/controller.mjs";
|
|
8
|
+
import { useScrollRestoration } from "./router/scrollRestoration/index.mjs";
|
|
9
|
+
import { usePageScrollRestoration, useScrollViewRestoration } from "./router/scrollRestoration/adapters.mjs";
|
|
7
10
|
import { useRouter } from "./router/useRouter.mjs";
|
|
8
11
|
|
|
9
|
-
export { NavigationFailureType, createNavigationFailure, createRouter, isNavigationFailure, parseQuery, resolveRouteLocation, stringifyQuery, useNativePageRouter, useNativeRouter, useRoute, useRouter };
|
|
12
|
+
export { NavigationFailureType, createNavigationFailure, createRouter, createScrollRestoration, isNavigationFailure, parseQuery, resolveRouteLocation, stringifyQuery, useNativePageRouter, useNativeRouter, usePageScrollRestoration, useRoute, useRouter, useScrollRestoration, useScrollViewRestoration };
|
|
@@ -6,7 +6,7 @@ function createDiagnosticsLogger(mode) {
|
|
|
6
6
|
if (mode === "off") return;
|
|
7
7
|
return (info) => {
|
|
8
8
|
if (mode === "fallback" && !isFallbackReason(info.reason)) return;
|
|
9
|
-
const bytes = typeof info.bytes === "number" ? info.bytes : info.estimatedBytes;
|
|
9
|
+
const bytes = info.phase ? info.phase.dispatch?.payloadBytes : typeof info.bytes === "number" ? info.bytes : info.estimatedBytes;
|
|
10
10
|
const bytesText = typeof bytes === "number" ? `${bytes}B` : "unknown";
|
|
11
11
|
const parts = [
|
|
12
12
|
`mode=${info.mode}`,
|
|
@@ -17,6 +17,10 @@ function createDiagnosticsLogger(mode) {
|
|
|
17
17
|
];
|
|
18
18
|
if (typeof info.revision === "number") parts.push(`revision=${info.revision}`);
|
|
19
19
|
if (typeof info.committedRevision === "number") parts.push(`committedRevision=${info.committedRevision}`);
|
|
20
|
+
if (info.phase) {
|
|
21
|
+
const phase = info.phase;
|
|
22
|
+
parts.push(`phase=${phase.name}`, `observer=${phase.observerId}`, `result=${phase.result}`, `completion=${phase.completion}`, `dispatch=${phase.dispatch?.id ?? "unknown"}`, `prepareMs=${phase.prepareDurationMs ?? "unknown"}`, `dispatchMs=${phase.dispatch?.durationMs ?? "unknown"}`, `commitMs=${phase.commitDurationMs ?? "unknown"}`, "visibleAt=unknown");
|
|
23
|
+
}
|
|
20
24
|
if (typeof info.mergedSiblingParents === "number") parts.push(`mergedParents=${info.mergedSiblingParents}`);
|
|
21
25
|
if (typeof info.computedDirtyKeys === "number") parts.push(`computedDirty=${info.computedDirtyKeys}`);
|
|
22
26
|
if (typeof info.flushCount === "number") parts.push(`flushes=${info.flushCount}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.mjs","names":[],"sources":["../../../../src/runtime/app/diagnostics.ts"],"sourcesContent":["import type { SetDataDebugInfo } from '../types'\n\nfunction isFallbackReason(reason: SetDataDebugInfo['reason']) {\n return reason !== 'patch' && reason !== 'diff'\n}\n\nexport function createDiagnosticsLogger(mode: 'off' | 'fallback' | 'always') {\n if (mode === 'off') {\n return undefined\n }\n return (info: SetDataDebugInfo) => {\n if (mode === 'fallback' && !isFallbackReason(info.reason)) {\n return\n }\n const bytes = typeof info.bytes === 'number' ? info.bytes : info.estimatedBytes\n const bytesText = typeof bytes === 'number' ? `${bytes}B` : 'unknown'\n const parts = [\n `mode=${info.mode}`,\n `reason=${info.reason}`,\n `pending=${info.pendingPatchKeys}`,\n `keys=${info.payloadKeys}`,\n `bytes=${bytesText}`,\n ]\n if (typeof info.revision === 'number') {\n parts.push(`revision=${info.revision}`)\n }\n if (typeof info.committedRevision === 'number') {\n parts.push(`committedRevision=${info.committedRevision}`)\n }\n if (typeof info.mergedSiblingParents === 'number') {\n parts.push(`mergedParents=${info.mergedSiblingParents}`)\n }\n if (typeof info.computedDirtyKeys === 'number') {\n parts.push(`computedDirty=${info.computedDirtyKeys}`)\n }\n if (typeof info.flushCount === 'number') {\n parts.push(`flushes=${info.flushCount}`)\n }\n if (typeof info.windowMs === 'number') {\n parts.push(`window=${info.windowMs}ms`)\n }\n if (info.targetLabel) {\n parts.push(`target=${info.targetLabel}`)\n }\n if (info.bindings?.length) {\n const bindings = info.bindings.map((binding) => {\n const start = binding.sourceLocation?.start\n return start\n ? `${binding.id}@${binding.sourceFile}:${start.line}:${start.column}`\n : `${binding.id}@${binding.sourceFile}`\n })\n parts.push(`bindings=${bindings.join(',')}`)\n }\n if (info.message) {\n parts.push(`message=${info.message}`)\n }\n const message = `[wevu:setData] ${parts.join(' ')}`\n if (isFallbackReason(info.reason)) {\n // eslint-disable-next-line no-console\n console.warn(message)\n return\n }\n // eslint-disable-next-line no-console\n console.info(message)\n }\n}\n"],"mappings":";AAEA,SAAS,iBAAiB,QAAoC;CAC5D,OAAO,WAAW,WAAW,WAAW;AAC1C;AAEA,SAAgB,wBAAwB,MAAqC;CAC3E,IAAI,SAAS,OACX;CAEF,QAAQ,SAA2B;EACjC,IAAI,SAAS,cAAc,CAAC,iBAAiB,KAAK,MAAM,GACtD;EAEF,MAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAK;
|
|
1
|
+
{"version":3,"file":"diagnostics.mjs","names":[],"sources":["../../../../src/runtime/app/diagnostics.ts"],"sourcesContent":["import type { SetDataDebugInfo } from '../types'\n\nfunction isFallbackReason(reason: SetDataDebugInfo['reason']) {\n return reason !== 'patch' && reason !== 'diff'\n}\n\nexport function createDiagnosticsLogger(mode: 'off' | 'fallback' | 'always') {\n if (mode === 'off') {\n return undefined\n }\n return (info: SetDataDebugInfo) => {\n if (mode === 'fallback' && !isFallbackReason(info.reason)) {\n return\n }\n const bytes = info.phase\n ? info.phase.dispatch?.payloadBytes\n : typeof info.bytes === 'number' ? info.bytes : info.estimatedBytes\n const bytesText = typeof bytes === 'number' ? `${bytes}B` : 'unknown'\n const parts = [\n `mode=${info.mode}`,\n `reason=${info.reason}`,\n `pending=${info.pendingPatchKeys}`,\n `keys=${info.payloadKeys}`,\n `bytes=${bytesText}`,\n ]\n if (typeof info.revision === 'number') {\n parts.push(`revision=${info.revision}`)\n }\n if (typeof info.committedRevision === 'number') {\n parts.push(`committedRevision=${info.committedRevision}`)\n }\n if (info.phase) {\n const phase = info.phase\n parts.push(\n `phase=${phase.name}`,\n `observer=${phase.observerId}`,\n `result=${phase.result}`,\n `completion=${phase.completion}`,\n `dispatch=${phase.dispatch?.id ?? 'unknown'}`,\n `prepareMs=${phase.prepareDurationMs ?? 'unknown'}`,\n `dispatchMs=${phase.dispatch?.durationMs ?? 'unknown'}`,\n `commitMs=${phase.commitDurationMs ?? 'unknown'}`,\n 'visibleAt=unknown',\n )\n }\n if (typeof info.mergedSiblingParents === 'number') {\n parts.push(`mergedParents=${info.mergedSiblingParents}`)\n }\n if (typeof info.computedDirtyKeys === 'number') {\n parts.push(`computedDirty=${info.computedDirtyKeys}`)\n }\n if (typeof info.flushCount === 'number') {\n parts.push(`flushes=${info.flushCount}`)\n }\n if (typeof info.windowMs === 'number') {\n parts.push(`window=${info.windowMs}ms`)\n }\n if (info.targetLabel) {\n parts.push(`target=${info.targetLabel}`)\n }\n if (info.bindings?.length) {\n const bindings = info.bindings.map((binding) => {\n const start = binding.sourceLocation?.start\n return start\n ? `${binding.id}@${binding.sourceFile}:${start.line}:${start.column}`\n : `${binding.id}@${binding.sourceFile}`\n })\n parts.push(`bindings=${bindings.join(',')}`)\n }\n if (info.message) {\n parts.push(`message=${info.message}`)\n }\n const message = `[wevu:setData] ${parts.join(' ')}`\n if (isFallbackReason(info.reason)) {\n // eslint-disable-next-line no-console\n console.warn(message)\n return\n }\n // eslint-disable-next-line no-console\n console.info(message)\n }\n}\n"],"mappings":";AAEA,SAAS,iBAAiB,QAAoC;CAC5D,OAAO,WAAW,WAAW,WAAW;AAC1C;AAEA,SAAgB,wBAAwB,MAAqC;CAC3E,IAAI,SAAS,OACX;CAEF,QAAQ,SAA2B;EACjC,IAAI,SAAS,cAAc,CAAC,iBAAiB,KAAK,MAAM,GACtD;EAEF,MAAM,QAAQ,KAAK,QACf,KAAK,MAAM,UAAU,eACrB,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAK;EACvD,MAAM,YAAY,OAAO,UAAU,WAAW,GAAG,MAAM,KAAK;EAC5D,MAAM,QAAQ;GACZ,QAAQ,KAAK;GACb,UAAU,KAAK;GACf,WAAW,KAAK;GAChB,QAAQ,KAAK;GACb,SAAS;EACX;EACA,IAAI,OAAO,KAAK,aAAa,UAC3B,MAAM,KAAK,YAAY,KAAK,UAAU;EAExC,IAAI,OAAO,KAAK,sBAAsB,UACpC,MAAM,KAAK,qBAAqB,KAAK,mBAAmB;EAE1D,IAAI,KAAK,OAAO;GACd,MAAM,QAAQ,KAAK;GACnB,MAAM,KACJ,SAAS,MAAM,QACf,YAAY,MAAM,cAClB,UAAU,MAAM,UAChB,cAAc,MAAM,cACpB,YAAY,MAAM,UAAU,MAAM,aAClC,aAAa,MAAM,qBAAqB,aACxC,cAAc,MAAM,UAAU,cAAc,aAC5C,YAAY,MAAM,oBAAoB,aACtC,mBACF;EACF;EACA,IAAI,OAAO,KAAK,yBAAyB,UACvC,MAAM,KAAK,iBAAiB,KAAK,sBAAsB;EAEzD,IAAI,OAAO,KAAK,sBAAsB,UACpC,MAAM,KAAK,iBAAiB,KAAK,mBAAmB;EAEtD,IAAI,OAAO,KAAK,eAAe,UAC7B,MAAM,KAAK,WAAW,KAAK,YAAY;EAEzC,IAAI,OAAO,KAAK,aAAa,UAC3B,MAAM,KAAK,UAAU,KAAK,SAAS,GAAG;EAExC,IAAI,KAAK,aACP,MAAM,KAAK,UAAU,KAAK,aAAa;EAEzC,IAAI,KAAK,UAAU,QAAQ;GACzB,MAAM,WAAW,KAAK,SAAS,KAAK,YAAY;IAC9C,MAAM,QAAQ,QAAQ,gBAAgB;IACtC,OAAO,QACH,GAAG,QAAQ,GAAG,GAAG,QAAQ,WAAW,GAAG,MAAM,KAAK,GAAG,MAAM,WAC3D,GAAG,QAAQ,GAAG,GAAG,QAAQ;GAC/B,CAAC;GACD,MAAM,KAAK,YAAY,SAAS,KAAK,GAAG,GAAG;EAC7C;EACA,IAAI,KAAK,SACP,MAAM,KAAK,WAAW,KAAK,SAAS;EAEtC,MAAM,UAAU,kBAAkB,MAAM,KAAK,GAAG;EAChD,IAAI,iBAAiB,KAAK,MAAM,GAAG;GAEjC,QAAQ,KAAK,OAAO;GACpB;EACF;EAEA,QAAQ,KAAK,OAAO;CACtB;AACF"}
|
|
@@ -76,7 +76,7 @@ function createRuntimeMount(options) {
|
|
|
76
76
|
const value = state[key];
|
|
77
77
|
if (hasTrackableSetupBinding(value)) trackedSetupReactiveKeys.add(key);
|
|
78
78
|
});
|
|
79
|
-
const { includeComputed, setDataStrategy, maxPatchKeys, maxPayloadBytes, mergeSiblingThreshold, mergeSiblingMaxInflationRatio, mergeSiblingMaxParentBytes, mergeSiblingSkipArray, computedCompare, computedCompareMaxDepth, computedCompareMaxKeys, prelinkMaxDepth, prelinkMaxKeys, debug, diagnostics, loopWarning, debugWhen, debugSampleRate, elevateTopKeyThreshold, toPlainMaxDepth, toPlainMaxKeys, includeFunctions, functionPaths, shouldIncludeKey } = resolveSetDataOptions(setDataOptions);
|
|
79
|
+
const { includeComputed, setDataStrategy, maxPatchKeys, maxPayloadBytes, mergeSiblingThreshold, mergeSiblingMaxInflationRatio, mergeSiblingMaxParentBytes, mergeSiblingSkipArray, computedCompare, computedCompareMaxDepth, computedCompareMaxKeys, prelinkMaxDepth, prelinkMaxKeys, debug, diagnostics, loopWarning, debugWhen, debugSampleRate, debugPhases, elevateTopKeyThreshold, toPlainMaxDepth, toPlainMaxKeys, includeFunctions, functionPaths, shouldIncludeKey } = resolveSetDataOptions(setDataOptions);
|
|
80
80
|
const diagnosticsLogger = createDiagnosticsLogger(diagnostics);
|
|
81
81
|
const loopWarningLogger = diagnostics === "off" && loopWarning ? createDiagnosticsLogger("fallback") : void 0;
|
|
82
82
|
const mergedDebug = debug || diagnosticsLogger || loopWarningLogger ? (info) => {
|
|
@@ -128,6 +128,7 @@ function createRuntimeMount(options) {
|
|
|
128
128
|
debug: mergedDebug,
|
|
129
129
|
debugWhen: mergedDebugWhen,
|
|
130
130
|
debugSampleRate,
|
|
131
|
+
debugPhases,
|
|
131
132
|
bindingManifest,
|
|
132
133
|
loopWarning,
|
|
133
134
|
targetLabel,
|
|
@@ -138,6 +139,10 @@ function createRuntimeMount(options) {
|
|
|
138
139
|
};
|
|
139
140
|
const scheduler = setDataStrategy === "patch" ? requireRuntimeCapability("patchStrategy", "createRuntimeMount(setData.strategy=\"patch\")").createScheduler(schedulerOptions) : createSetDataScheduler(schedulerOptions);
|
|
140
141
|
const job = () => scheduler.job();
|
|
142
|
+
const flushSetupSnapshotSync = () => {
|
|
143
|
+
tracker?.();
|
|
144
|
+
scheduler.job();
|
|
145
|
+
};
|
|
141
146
|
tracker = effect(() => {
|
|
142
147
|
touchReactive(state);
|
|
143
148
|
const runtimeProps = state[WEVU_PROPS_KEY];
|
|
@@ -216,13 +221,13 @@ function createRuntimeMount(options) {
|
|
|
216
221
|
}
|
|
217
222
|
try {
|
|
218
223
|
Object.defineProperty(runtimeInstance, "__wevu_flushSetupSnapshotSync", {
|
|
219
|
-
value:
|
|
224
|
+
value: flushSetupSnapshotSync,
|
|
220
225
|
configurable: true,
|
|
221
226
|
enumerable: false,
|
|
222
227
|
writable: false
|
|
223
228
|
});
|
|
224
229
|
} catch {
|
|
225
|
-
runtimeInstance.__wevu_flushSetupSnapshotSync =
|
|
230
|
+
runtimeInstance.__wevu_flushSetupSnapshotSync = flushSetupSnapshotSync;
|
|
226
231
|
}
|
|
227
232
|
try {
|
|
228
233
|
Object.defineProperty(runtimeInstance, "__wevu_cloneDispatchedSnapshot", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount.mjs","names":[],"sources":["../../../../src/runtime/app/mount.ts"],"sourcesContent":["import type { WevuRuntimeBindingManifestV1 } from '@weapp-core/constants'\nimport type { WatchOptions, WatchStopHandle } from '../../reactivity'\nimport type {\n AppConfig,\n ComputedDefinitions,\n CreateAppOptions,\n ExtractComputed,\n MethodDefinitions,\n MiniProgramAdapter,\n RuntimeInstance,\n SetDataDebugInfo,\n} from '../types'\nimport type { CommitAwareSetDataAdapter } from './setData/commitTracker'\nimport {\n WEVU_ATTRS_KEY,\n WEVU_PROPS_DERIVED_KEYS_KEY,\n WEVU_PROPS_KEY,\n WEVU_SETUP_STATE_KEY,\n} from '@weapp-core/constants'\nimport { effect, isReactive, reactive, shallowReactive, stop, touchReactive, watch } from '../../reactivity'\nimport { queueJob } from '../../scheduler'\nimport { hasOwn } from '../../utils'\nimport { createBindModel } from '../bindModel'\nimport { requireRuntimeCapability } from '../capabilities'\nimport { hasTrackableSetupBinding, touchSetupBinding } from '../setupTracking'\nimport { createRuntimeContext } from './context'\nimport { createDiagnosticsLogger } from './diagnostics'\nimport { createSetDataScheduler } from './setData/scheduler'\nimport { resolveSetDataOptions } from './setDataOptions'\n\nfunction createWatchStopHandle(cleanup: () => void, baseHandle?: WatchStopHandle): WatchStopHandle {\n const stopHandle = (() => {\n cleanup()\n }) as WatchStopHandle\n stopHandle.stop = () => stopHandle()\n stopHandle.pause = () => {\n baseHandle?.pause?.()\n }\n stopHandle.resume = () => {\n baseHandle?.resume?.()\n }\n return stopHandle\n}\n\ntype RuntimeInstanceWithSetupMethodsVersion<\n D extends object,\n C extends ComputedDefinitions,\n M extends MethodDefinitions,\n> = RuntimeInstance<D, C, M> & {\n __wevu_touchSetupMethodsVersion?: () => void\n __wevu_flushSetupSnapshotSync?: () => void\n __wevu_cloneDispatchedSnapshot?: () => Record<string, any>\n __wevu_trackSetupReactiveKey?: (key: string) => void\n}\n\nfunction resolveDataOption<D extends object>(data: CreateAppOptions<D, any, any>['data']): D {\n if (typeof data === 'function') {\n return data()\n }\n return (data ?? {}) as D\n}\n\nexport function createRuntimeMount<D extends object, C extends ComputedDefinitions, M extends MethodDefinitions>(options: {\n data: CreateAppOptions<D, C, M>['data']\n resolvedComputed: C\n resolvedMethods: M\n appConfig: AppConfig\n setDataOptions: CreateAppOptions<D, C, M>['setData']\n bindingManifest?: WevuRuntimeBindingManifestV1\n}) {\n const {\n data,\n resolvedComputed,\n resolvedMethods,\n appConfig,\n setDataOptions,\n bindingManifest,\n } = options\n\n return (adapter?: MiniProgramAdapter): RuntimeInstance<D, C, M> => {\n if (setDataOptions?.strategy === 'patch') {\n requireRuntimeCapability('patchStrategy', 'createRuntimeMount(setData.strategy=\"patch\")')\n }\n const rawState = resolveDataOption(data)\n const adapterInitialProps = (adapter as any)?.__wevu_initialProps\n // 预置 props 容器,确保编译器生成的 this.__wevuProps 回退表达式\n // 在 computed 首次求值阶段即可建立响应式依赖。\n if (rawState && typeof rawState === 'object' && !hasOwn(rawState as object, WEVU_PROPS_KEY)) {\n try {\n Object.defineProperty(rawState as object, WEVU_PROPS_KEY, {\n value: shallowReactive(Object.create(null)),\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n // 若 data 返回对象不可扩展,则跳过预置,后续由 mount 阶段兜底注入。\n }\n }\n const rawProps = rawState && typeof rawState === 'object'\n ? (rawState as any)[WEVU_PROPS_KEY]\n : undefined\n if (rawProps && typeof rawProps === 'object' && adapterInitialProps && typeof adapterInitialProps === 'object') {\n Object.assign(rawProps, adapterInitialProps)\n }\n const state = reactive(rawState)\n const setupState = reactive(Object.create(null))\n const adapterSnapshotOmitKeys = (adapter as any)?.__wevu_snapshotOmitKeys\n const deferInitialSnapshot = Boolean((adapter as any)?.__wevu_deferInitialSnapshot)\n const adapterInitialSnapshot = (adapter as any)?.__wevu_initialSnapshot\n const adapterInitialState = (adapter as any)?.__wevu_initialState\n const snapshotOmitKeys = new Set<string>(\n adapterSnapshotOmitKeys instanceof Set\n ? adapterSnapshotOmitKeys\n : Array.isArray(adapterSnapshotOmitKeys)\n ? adapterSnapshotOmitKeys\n : [],\n )\n if (rawState && typeof rawState === 'object' && !hasOwn(rawState as object, WEVU_SETUP_STATE_KEY)) {\n try {\n Object.defineProperty(rawState as object, WEVU_SETUP_STATE_KEY, {\n value: setupState,\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n // 若 data 返回对象不可扩展,则跳过预置,后续由注册阶段兜底注入。\n }\n }\n if (rawState && typeof rawState === 'object' && adapterInitialState && typeof adapterInitialState === 'object') {\n for (const [key, value] of Object.entries(adapterInitialState as Record<string, unknown>)) {\n if (snapshotOmitKeys.has(key)) {\n continue\n }\n ;(rawState as Record<string, unknown>)[key] = value\n }\n }\n const computedDefs = resolvedComputed\n const methodDefs = resolvedMethods\n\n let mounted = true\n const stopHandles: WatchStopHandle[] = []\n const trackedSetupReactiveKeys = new Set<string>()\n Object.keys(state as any).forEach((key) => {\n const value = (state as any)[key]\n if (hasTrackableSetupBinding(value)) {\n trackedSetupReactiveKeys.add(key)\n }\n })\n\n const {\n includeComputed,\n setDataStrategy,\n maxPatchKeys,\n maxPayloadBytes,\n mergeSiblingThreshold,\n mergeSiblingMaxInflationRatio,\n mergeSiblingMaxParentBytes,\n mergeSiblingSkipArray,\n computedCompare,\n computedCompareMaxDepth,\n computedCompareMaxKeys,\n prelinkMaxDepth,\n prelinkMaxKeys,\n debug,\n diagnostics,\n loopWarning,\n debugWhen,\n debugSampleRate,\n elevateTopKeyThreshold,\n toPlainMaxDepth,\n toPlainMaxKeys,\n includeFunctions,\n functionPaths,\n shouldIncludeKey,\n } = resolveSetDataOptions(setDataOptions)\n const diagnosticsLogger = createDiagnosticsLogger(diagnostics)\n const loopWarningLogger = diagnostics === 'off' && loopWarning\n ? createDiagnosticsLogger('fallback')\n : undefined\n const mergedDebug = (debug || diagnosticsLogger || loopWarningLogger)\n ? (info: SetDataDebugInfo) => {\n if (typeof debug === 'function') {\n try {\n debug(info)\n }\n catch {\n // 用户调试回调不得阻止默认诊断。\n }\n }\n diagnosticsLogger?.(info)\n if (info.reason === 'loopWarning') {\n loopWarningLogger?.(info)\n }\n }\n : undefined\n const mergedDebugWhen = diagnostics === 'always'\n ? 'always'\n : debugWhen\n\n const {\n boundMethods,\n computedRefs,\n computedSetters,\n dirtyComputedKeys,\n computedProxy,\n publicInstance,\n touchSetupMethodsVersion,\n } = createRuntimeContext({\n state,\n setupState: setupState as Record<string, any>,\n computedDefs,\n methodDefs,\n appConfig,\n includeComputed,\n setDataStrategy,\n })\n\n const currentAdapter: CommitAwareSetDataAdapter = adapter ?? { setData: () => {} }\n const targetLabel = (currentAdapter as any).__wevu_targetLabel as string | undefined\n let tracker: ReturnType<typeof effect> | undefined\n const schedulerOptions = {\n state: state as any,\n setupState: setupState as any,\n snapshotOmitKeys,\n computedRefs,\n dirtyComputedKeys,\n includeComputed,\n setDataStrategy,\n computedCompare,\n computedCompareMaxDepth,\n computedCompareMaxKeys,\n currentAdapter,\n shouldIncludeKey,\n maxPatchKeys,\n maxPayloadBytes,\n mergeSiblingThreshold,\n mergeSiblingMaxInflationRatio,\n mergeSiblingMaxParentBytes,\n mergeSiblingSkipArray,\n elevateTopKeyThreshold,\n prelinkMaxDepth,\n prelinkMaxKeys,\n toPlainMaxDepth,\n toPlainMaxKeys,\n includeFunctions,\n functionPaths,\n debug: mergedDebug,\n debugWhen: mergedDebugWhen,\n debugSampleRate,\n bindingManifest,\n loopWarning,\n targetLabel,\n runTracker: () => tracker?.(),\n isMounted: () => mounted,\n initialSnapshot: adapterInitialSnapshot && typeof adapterInitialSnapshot === 'object'\n ? adapterInitialSnapshot\n : undefined,\n initialState: adapterInitialState && typeof adapterInitialState === 'object'\n ? adapterInitialState\n : undefined,\n }\n const scheduler = setDataStrategy === 'patch'\n ? requireRuntimeCapability('patchStrategy', 'createRuntimeMount(setData.strategy=\"patch\")')\n .createScheduler(schedulerOptions)\n : createSetDataScheduler(schedulerOptions)\n const job = () => scheduler.job()\n\n tracker = effect(\n () => {\n // 通过根版本信号跟踪任意状态变化\n touchReactive(state as any)\n // __wevuProps / __wevuAttrs 是非枚举属性,需显式跟踪,\n // 否则 props/attrs 更新不会触发 setData 调度。\n const runtimeProps = (state as any)[WEVU_PROPS_KEY]\n if (isReactive(runtimeProps)) {\n touchReactive(runtimeProps as any)\n }\n const runtimeAttrs = (state as any)[WEVU_ATTRS_KEY]\n if (isReactive(runtimeAttrs)) {\n touchReactive(runtimeAttrs as any)\n }\n // 在 setup 返回的 ref/computedRef 变更不会提升 reactive 根版本:\n // 仅跟踪这些明确注册过的键,避免每轮 flush 扫描整份 state。\n trackedSetupReactiveKeys.forEach((key) => {\n const v = (setupState as any)[key] ?? (state as any)[key]\n // setup 返回的组合式对象常常是“普通对象 + 内含 refs/reactive”,\n // 这里递归触达内部响应式源,确保异步更新也能继续驱动 setData。\n touchSetupBinding(v)\n })\n },\n {\n lazy: true,\n scheduler: () => queueJob(job),\n },\n )\n\n if (!deferInitialSnapshot) {\n job()\n }\n\n stopHandles.push(createWatchStopHandle(() => stop(tracker)))\n scheduler.start?.()\n if (scheduler.dispose) {\n stopHandles.push(createWatchStopHandle(scheduler.dispose))\n }\n\n function registerWatch<T>(\n source: (() => T) | Record<string, any>,\n cb: (value: T, oldValue: T) => void,\n watchOptions?: WatchOptions,\n ): WatchStopHandle {\n const stopHandle = watch(source as any, (value: T, oldValue: T) => cb(value, oldValue), watchOptions)\n stopHandles.push(stopHandle)\n return createWatchStopHandle(() => {\n stopHandle()\n const index = stopHandles.indexOf(stopHandle)\n if (index >= 0) {\n stopHandles.splice(index, 1)\n }\n }, stopHandle)\n }\n\n const bindModel = createBindModel(\n publicInstance as any,\n state as any,\n computedRefs,\n computedSetters,\n setupState as Record<string, any>,\n )\n\n const unmount = () => {\n if (!mounted) {\n return\n }\n mounted = false\n scheduler.dispose?.()\n try {\n currentAdapter.__wevu_disposeSetData?.()\n }\n catch {\n // 卸载阶段继续清理其余运行时资源。\n }\n stopHandles.forEach((handle) => {\n try {\n handle()\n }\n catch {\n // 卸载阶段忽略 stop 抛错,确保其余清理继续\n }\n })\n stopHandles.length = 0\n }\n\n const runtimeInstance: RuntimeInstance<D, C, M> = {\n get state() {\n return state\n },\n get setupState() {\n return setupState as Record<string, any>\n },\n get proxy() {\n return publicInstance\n },\n get methods() {\n return boundMethods\n },\n get computed() {\n return computedProxy as Readonly<ExtractComputed<C>>\n },\n get adapter() {\n return currentAdapter\n },\n bindModel,\n watch: registerWatch,\n snapshot: () => scheduler.snapshot(),\n unmount,\n }\n\n try {\n Object.defineProperty(runtimeInstance, '__wevu_touchSetupMethodsVersion', {\n value: touchSetupMethodsVersion,\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n ;(runtimeInstance as RuntimeInstanceWithSetupMethodsVersion<D, C, M>).__wevu_touchSetupMethodsVersion = touchSetupMethodsVersion\n }\n\n try {\n Object.defineProperty(runtimeInstance, '__wevu_flushSetupSnapshotSync', {\n value: job,\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n ;(runtimeInstance as RuntimeInstanceWithSetupMethodsVersion<D, C, M>).__wevu_flushSetupSnapshotSync = job\n }\n\n try {\n Object.defineProperty(runtimeInstance, '__wevu_cloneDispatchedSnapshot', {\n value: scheduler.cloneLatestSnapshot,\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n ;(runtimeInstance as RuntimeInstanceWithSetupMethodsVersion<D, C, M>).__wevu_cloneDispatchedSnapshot = scheduler.cloneLatestSnapshot\n }\n\n try {\n Object.defineProperty(runtimeInstance, '__wevu_trackSetupReactiveKey', {\n value: (key: string) => {\n trackedSetupReactiveKeys.add(key)\n },\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n ;(runtimeInstance as RuntimeInstanceWithSetupMethodsVersion<D, C, M>).__wevu_trackSetupReactiveKey = (key: string) => {\n trackedSetupReactiveKeys.add(key)\n }\n }\n\n try {\n Object.defineProperty(runtimeInstance, WEVU_PROPS_DERIVED_KEYS_KEY, {\n value: snapshotOmitKeys,\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n ;(runtimeInstance as any)[WEVU_PROPS_DERIVED_KEYS_KEY] = snapshotOmitKeys\n }\n\n return runtimeInstance\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mount.mjs","names":[],"sources":["../../../../src/runtime/app/mount.ts"],"sourcesContent":["import type { WevuRuntimeBindingManifestV1 } from '@weapp-core/constants'\nimport type { WatchOptions, WatchStopHandle } from '../../reactivity'\nimport type {\n AppConfig,\n ComputedDefinitions,\n CreateAppOptions,\n ExtractComputed,\n MethodDefinitions,\n MiniProgramAdapter,\n RuntimeInstance,\n SetDataDebugInfo,\n} from '../types'\nimport type { CommitAwareSetDataAdapter } from './setData/commitTracker'\nimport {\n WEVU_ATTRS_KEY,\n WEVU_PROPS_DERIVED_KEYS_KEY,\n WEVU_PROPS_KEY,\n WEVU_SETUP_STATE_KEY,\n} from '@weapp-core/constants'\nimport { effect, isReactive, reactive, shallowReactive, stop, touchReactive, watch } from '../../reactivity'\nimport { queueJob } from '../../scheduler'\nimport { hasOwn } from '../../utils'\nimport { createBindModel } from '../bindModel'\nimport { requireRuntimeCapability } from '../capabilities'\nimport { hasTrackableSetupBinding, touchSetupBinding } from '../setupTracking'\nimport { createRuntimeContext } from './context'\nimport { createDiagnosticsLogger } from './diagnostics'\nimport { createSetDataScheduler } from './setData/scheduler'\nimport { resolveSetDataOptions } from './setDataOptions'\n\nfunction createWatchStopHandle(cleanup: () => void, baseHandle?: WatchStopHandle): WatchStopHandle {\n const stopHandle = (() => {\n cleanup()\n }) as WatchStopHandle\n stopHandle.stop = () => stopHandle()\n stopHandle.pause = () => {\n baseHandle?.pause?.()\n }\n stopHandle.resume = () => {\n baseHandle?.resume?.()\n }\n return stopHandle\n}\n\ntype RuntimeInstanceWithSetupMethodsVersion<\n D extends object,\n C extends ComputedDefinitions,\n M extends MethodDefinitions,\n> = RuntimeInstance<D, C, M> & {\n __wevu_touchSetupMethodsVersion?: () => void\n __wevu_flushSetupSnapshotSync?: () => void\n __wevu_cloneDispatchedSnapshot?: () => Record<string, any>\n __wevu_trackSetupReactiveKey?: (key: string) => void\n}\n\nfunction resolveDataOption<D extends object>(data: CreateAppOptions<D, any, any>['data']): D {\n if (typeof data === 'function') {\n return data()\n }\n return (data ?? {}) as D\n}\n\nexport function createRuntimeMount<D extends object, C extends ComputedDefinitions, M extends MethodDefinitions>(options: {\n data: CreateAppOptions<D, C, M>['data']\n resolvedComputed: C\n resolvedMethods: M\n appConfig: AppConfig\n setDataOptions: CreateAppOptions<D, C, M>['setData']\n bindingManifest?: WevuRuntimeBindingManifestV1\n}) {\n const {\n data,\n resolvedComputed,\n resolvedMethods,\n appConfig,\n setDataOptions,\n bindingManifest,\n } = options\n\n return (adapter?: MiniProgramAdapter): RuntimeInstance<D, C, M> => {\n if (setDataOptions?.strategy === 'patch') {\n requireRuntimeCapability('patchStrategy', 'createRuntimeMount(setData.strategy=\"patch\")')\n }\n const rawState = resolveDataOption(data)\n const adapterInitialProps = (adapter as any)?.__wevu_initialProps\n // 预置 props 容器,确保编译器生成的 this.__wevuProps 回退表达式\n // 在 computed 首次求值阶段即可建立响应式依赖。\n if (rawState && typeof rawState === 'object' && !hasOwn(rawState as object, WEVU_PROPS_KEY)) {\n try {\n Object.defineProperty(rawState as object, WEVU_PROPS_KEY, {\n value: shallowReactive(Object.create(null)),\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n // 若 data 返回对象不可扩展,则跳过预置,后续由 mount 阶段兜底注入。\n }\n }\n const rawProps = rawState && typeof rawState === 'object'\n ? (rawState as any)[WEVU_PROPS_KEY]\n : undefined\n if (rawProps && typeof rawProps === 'object' && adapterInitialProps && typeof adapterInitialProps === 'object') {\n Object.assign(rawProps, adapterInitialProps)\n }\n const state = reactive(rawState)\n const setupState = reactive(Object.create(null))\n const adapterSnapshotOmitKeys = (adapter as any)?.__wevu_snapshotOmitKeys\n const deferInitialSnapshot = Boolean((adapter as any)?.__wevu_deferInitialSnapshot)\n const adapterInitialSnapshot = (adapter as any)?.__wevu_initialSnapshot\n const adapterInitialState = (adapter as any)?.__wevu_initialState\n const snapshotOmitKeys = new Set<string>(\n adapterSnapshotOmitKeys instanceof Set\n ? adapterSnapshotOmitKeys\n : Array.isArray(adapterSnapshotOmitKeys)\n ? adapterSnapshotOmitKeys\n : [],\n )\n if (rawState && typeof rawState === 'object' && !hasOwn(rawState as object, WEVU_SETUP_STATE_KEY)) {\n try {\n Object.defineProperty(rawState as object, WEVU_SETUP_STATE_KEY, {\n value: setupState,\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n // 若 data 返回对象不可扩展,则跳过预置,后续由注册阶段兜底注入。\n }\n }\n if (rawState && typeof rawState === 'object' && adapterInitialState && typeof adapterInitialState === 'object') {\n for (const [key, value] of Object.entries(adapterInitialState as Record<string, unknown>)) {\n if (snapshotOmitKeys.has(key)) {\n continue\n }\n ;(rawState as Record<string, unknown>)[key] = value\n }\n }\n const computedDefs = resolvedComputed\n const methodDefs = resolvedMethods\n\n let mounted = true\n const stopHandles: WatchStopHandle[] = []\n const trackedSetupReactiveKeys = new Set<string>()\n Object.keys(state as any).forEach((key) => {\n const value = (state as any)[key]\n if (hasTrackableSetupBinding(value)) {\n trackedSetupReactiveKeys.add(key)\n }\n })\n\n const {\n includeComputed,\n setDataStrategy,\n maxPatchKeys,\n maxPayloadBytes,\n mergeSiblingThreshold,\n mergeSiblingMaxInflationRatio,\n mergeSiblingMaxParentBytes,\n mergeSiblingSkipArray,\n computedCompare,\n computedCompareMaxDepth,\n computedCompareMaxKeys,\n prelinkMaxDepth,\n prelinkMaxKeys,\n debug,\n diagnostics,\n loopWarning,\n debugWhen,\n debugSampleRate,\n debugPhases,\n elevateTopKeyThreshold,\n toPlainMaxDepth,\n toPlainMaxKeys,\n includeFunctions,\n functionPaths,\n shouldIncludeKey,\n } = resolveSetDataOptions(setDataOptions)\n const diagnosticsLogger = createDiagnosticsLogger(diagnostics)\n const loopWarningLogger = diagnostics === 'off' && loopWarning\n ? createDiagnosticsLogger('fallback')\n : undefined\n const mergedDebug = (debug || diagnosticsLogger || loopWarningLogger)\n ? (info: SetDataDebugInfo) => {\n if (typeof debug === 'function') {\n try {\n debug(info)\n }\n catch {\n // 用户调试回调不得阻止默认诊断。\n }\n }\n diagnosticsLogger?.(info)\n if (info.reason === 'loopWarning') {\n loopWarningLogger?.(info)\n }\n }\n : undefined\n const mergedDebugWhen = diagnostics === 'always'\n ? 'always'\n : debugWhen\n\n const {\n boundMethods,\n computedRefs,\n computedSetters,\n dirtyComputedKeys,\n computedProxy,\n publicInstance,\n touchSetupMethodsVersion,\n } = createRuntimeContext({\n state,\n setupState: setupState as Record<string, any>,\n computedDefs,\n methodDefs,\n appConfig,\n includeComputed,\n setDataStrategy,\n })\n\n const currentAdapter: CommitAwareSetDataAdapter = adapter ?? { setData: () => {} }\n const targetLabel = (currentAdapter as any).__wevu_targetLabel as string | undefined\n let tracker: ReturnType<typeof effect> | undefined\n const schedulerOptions = {\n state: state as any,\n setupState: setupState as any,\n snapshotOmitKeys,\n computedRefs,\n dirtyComputedKeys,\n includeComputed,\n setDataStrategy,\n computedCompare,\n computedCompareMaxDepth,\n computedCompareMaxKeys,\n currentAdapter,\n shouldIncludeKey,\n maxPatchKeys,\n maxPayloadBytes,\n mergeSiblingThreshold,\n mergeSiblingMaxInflationRatio,\n mergeSiblingMaxParentBytes,\n mergeSiblingSkipArray,\n elevateTopKeyThreshold,\n prelinkMaxDepth,\n prelinkMaxKeys,\n toPlainMaxDepth,\n toPlainMaxKeys,\n includeFunctions,\n functionPaths,\n debug: mergedDebug,\n debugWhen: mergedDebugWhen,\n debugSampleRate,\n debugPhases,\n bindingManifest,\n loopWarning,\n targetLabel,\n runTracker: () => tracker?.(),\n isMounted: () => mounted,\n initialSnapshot: adapterInitialSnapshot && typeof adapterInitialSnapshot === 'object'\n ? adapterInitialSnapshot\n : undefined,\n initialState: adapterInitialState && typeof adapterInitialState === 'object'\n ? adapterInitialState\n : undefined,\n }\n const scheduler = setDataStrategy === 'patch'\n ? requireRuntimeCapability('patchStrategy', 'createRuntimeMount(setData.strategy=\"patch\")')\n .createScheduler(schedulerOptions)\n : createSetDataScheduler(schedulerOptions)\n const job = () => scheduler.job()\n // HMR 延迟快照可能把 setup 状态恢复为与宿主相同的值;此时调度器不会因值变化重新运行\n // tracker。先主动触达一次新 setup 的响应式依赖,确保后续 ref/computed 更新仍能进入调度器。\n const flushSetupSnapshotSync = () => {\n tracker?.()\n scheduler.job()\n }\n\n tracker = effect(\n () => {\n // 通过根版本信号跟踪任意状态变化\n touchReactive(state as any)\n // __wevuProps / __wevuAttrs 是非枚举属性,需显式跟踪,\n // 否则 props/attrs 更新不会触发 setData 调度。\n const runtimeProps = (state as any)[WEVU_PROPS_KEY]\n if (isReactive(runtimeProps)) {\n touchReactive(runtimeProps as any)\n }\n const runtimeAttrs = (state as any)[WEVU_ATTRS_KEY]\n if (isReactive(runtimeAttrs)) {\n touchReactive(runtimeAttrs as any)\n }\n // 在 setup 返回的 ref/computedRef 变更不会提升 reactive 根版本:\n // 仅跟踪这些明确注册过的键,避免每轮 flush 扫描整份 state。\n trackedSetupReactiveKeys.forEach((key) => {\n const v = (setupState as any)[key] ?? (state as any)[key]\n // setup 返回的组合式对象常常是“普通对象 + 内含 refs/reactive”,\n // 这里递归触达内部响应式源,确保异步更新也能继续驱动 setData。\n touchSetupBinding(v)\n })\n },\n {\n lazy: true,\n scheduler: () => queueJob(job),\n },\n )\n\n if (!deferInitialSnapshot) {\n job()\n }\n\n stopHandles.push(createWatchStopHandle(() => stop(tracker)))\n scheduler.start?.()\n if (scheduler.dispose) {\n stopHandles.push(createWatchStopHandle(scheduler.dispose))\n }\n\n function registerWatch<T>(\n source: (() => T) | Record<string, any>,\n cb: (value: T, oldValue: T) => void,\n watchOptions?: WatchOptions,\n ): WatchStopHandle {\n const stopHandle = watch(source as any, (value: T, oldValue: T) => cb(value, oldValue), watchOptions)\n stopHandles.push(stopHandle)\n return createWatchStopHandle(() => {\n stopHandle()\n const index = stopHandles.indexOf(stopHandle)\n if (index >= 0) {\n stopHandles.splice(index, 1)\n }\n }, stopHandle)\n }\n\n const bindModel = createBindModel(\n publicInstance as any,\n state as any,\n computedRefs,\n computedSetters,\n setupState as Record<string, any>,\n )\n\n const unmount = () => {\n if (!mounted) {\n return\n }\n mounted = false\n scheduler.dispose?.()\n try {\n currentAdapter.__wevu_disposeSetData?.()\n }\n catch {\n // 卸载阶段继续清理其余运行时资源。\n }\n stopHandles.forEach((handle) => {\n try {\n handle()\n }\n catch {\n // 卸载阶段忽略 stop 抛错,确保其余清理继续\n }\n })\n stopHandles.length = 0\n }\n\n const runtimeInstance: RuntimeInstance<D, C, M> = {\n get state() {\n return state\n },\n get setupState() {\n return setupState as Record<string, any>\n },\n get proxy() {\n return publicInstance\n },\n get methods() {\n return boundMethods\n },\n get computed() {\n return computedProxy as Readonly<ExtractComputed<C>>\n },\n get adapter() {\n return currentAdapter\n },\n bindModel,\n watch: registerWatch,\n snapshot: () => scheduler.snapshot(),\n unmount,\n }\n\n try {\n Object.defineProperty(runtimeInstance, '__wevu_touchSetupMethodsVersion', {\n value: touchSetupMethodsVersion,\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n ;(runtimeInstance as RuntimeInstanceWithSetupMethodsVersion<D, C, M>).__wevu_touchSetupMethodsVersion = touchSetupMethodsVersion\n }\n\n try {\n Object.defineProperty(runtimeInstance, '__wevu_flushSetupSnapshotSync', {\n value: flushSetupSnapshotSync,\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n ;(runtimeInstance as RuntimeInstanceWithSetupMethodsVersion<D, C, M>).__wevu_flushSetupSnapshotSync = flushSetupSnapshotSync\n }\n\n try {\n Object.defineProperty(runtimeInstance, '__wevu_cloneDispatchedSnapshot', {\n value: scheduler.cloneLatestSnapshot,\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n ;(runtimeInstance as RuntimeInstanceWithSetupMethodsVersion<D, C, M>).__wevu_cloneDispatchedSnapshot = scheduler.cloneLatestSnapshot\n }\n\n try {\n Object.defineProperty(runtimeInstance, '__wevu_trackSetupReactiveKey', {\n value: (key: string) => {\n trackedSetupReactiveKeys.add(key)\n },\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n ;(runtimeInstance as RuntimeInstanceWithSetupMethodsVersion<D, C, M>).__wevu_trackSetupReactiveKey = (key: string) => {\n trackedSetupReactiveKeys.add(key)\n }\n }\n\n try {\n Object.defineProperty(runtimeInstance, WEVU_PROPS_DERIVED_KEYS_KEY, {\n value: snapshotOmitKeys,\n configurable: true,\n enumerable: false,\n writable: false,\n })\n }\n catch {\n ;(runtimeInstance as any)[WEVU_PROPS_DERIVED_KEYS_KEY] = snapshotOmitKeys\n }\n\n return runtimeInstance\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { observePhysicalDispatch } from "./observation.mjs";
|
|
1
2
|
import { cloneSnapshotValue } from "./snapshot.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/runtime/app/setData/commitTracker.ts
|
|
@@ -22,10 +23,13 @@ function observeSetDataCompletion(options) {
|
|
|
22
23
|
let settled = false;
|
|
23
24
|
let invoking = true;
|
|
24
25
|
let callbackCalled = false;
|
|
26
|
+
let observedReturn = false;
|
|
25
27
|
let returnIsAuthoritative = false;
|
|
28
|
+
let boundary = options.completion;
|
|
26
29
|
const settleOnce = (settlement, cause) => {
|
|
27
30
|
if (settled) return;
|
|
28
31
|
settled = true;
|
|
32
|
+
options.observer?.complete(boundary);
|
|
29
33
|
options.settle(settlement, cause);
|
|
30
34
|
};
|
|
31
35
|
const callback = () => {
|
|
@@ -37,17 +41,28 @@ function observeSetDataCompletion(options) {
|
|
|
37
41
|
if (options.completion === "callback") settleOnce("committed");
|
|
38
42
|
};
|
|
39
43
|
try {
|
|
44
|
+
if (options.observer && options.payload) observePhysicalDispatch(options.observer, options.payload);
|
|
40
45
|
const result = options.invoke(callback);
|
|
41
46
|
const resultIsThenable = isThenable(result);
|
|
42
47
|
returnIsAuthoritative = resultIsThenable;
|
|
43
48
|
invoking = false;
|
|
49
|
+
if (options.observer && !observedReturn) {
|
|
50
|
+
observedReturn = true;
|
|
51
|
+
options.observer.returned(Date.now());
|
|
52
|
+
}
|
|
44
53
|
if (resultIsThenable) {
|
|
54
|
+
boundary = "promise";
|
|
45
55
|
result.then(() => settleOnce("committed"), (cause) => settleOnce("failed", cause));
|
|
46
56
|
return;
|
|
47
57
|
}
|
|
48
58
|
if (options.completion === "return" || callbackCalled) settleOnce("committed");
|
|
49
59
|
} catch (cause) {
|
|
60
|
+
boundary = "throw";
|
|
50
61
|
invoking = false;
|
|
62
|
+
if (options.observer && !observedReturn) {
|
|
63
|
+
observedReturn = true;
|
|
64
|
+
options.observer.returned(Date.now());
|
|
65
|
+
}
|
|
51
66
|
settleOnce("failed", cause);
|
|
52
67
|
}
|
|
53
68
|
}
|
|
@@ -113,12 +128,17 @@ function createSetDataCommitTracker(options) {
|
|
|
113
128
|
}
|
|
114
129
|
};
|
|
115
130
|
const invalidateLedger = () => {
|
|
131
|
+
let abandonedObservations;
|
|
132
|
+
const result = state.disposed ? "disposed" : "abandoned";
|
|
116
133
|
let current = head;
|
|
117
134
|
while (current) {
|
|
118
135
|
const next = current.next;
|
|
119
136
|
current.inLedger = false;
|
|
120
137
|
current.next = void 0;
|
|
121
|
-
if (!current.physicalSettled)
|
|
138
|
+
if (!current.physicalSettled) {
|
|
139
|
+
current.status = "abandoned";
|
|
140
|
+
if (current.observation) (abandonedObservations ?? (abandonedObservations = [])).push(current.observation);
|
|
141
|
+
}
|
|
122
142
|
resolveRecord(current);
|
|
123
143
|
current = next;
|
|
124
144
|
}
|
|
@@ -126,6 +146,7 @@ function createSetDataCommitTracker(options) {
|
|
|
126
146
|
tail = void 0;
|
|
127
147
|
epoch += 1;
|
|
128
148
|
highestCompletedRevision = state.committedRevision;
|
|
149
|
+
abandonedObservations?.forEach((observation) => observation.finish(result));
|
|
129
150
|
};
|
|
130
151
|
const armRecovery = () => {
|
|
131
152
|
state.needsFullSnapshot = true;
|
|
@@ -168,7 +189,7 @@ function createSetDataCommitTracker(options) {
|
|
|
168
189
|
reportFailure("out-of-order", record, `revision ${record.revision} completed after committed revision ${state.committedRevision}`);
|
|
169
190
|
}
|
|
170
191
|
};
|
|
171
|
-
const
|
|
192
|
+
const applySettlement = (record, settlement, cause) => {
|
|
172
193
|
if (state.disposed || record.physicalSettled) return;
|
|
173
194
|
record.physicalSettled = true;
|
|
174
195
|
if (!record.inLedger || record.epoch !== epoch) {
|
|
@@ -197,6 +218,17 @@ function createSetDataCommitTracker(options) {
|
|
|
197
218
|
}
|
|
198
219
|
drainSucceededPrefix();
|
|
199
220
|
};
|
|
221
|
+
const settleRecord = (record, settlement, cause) => {
|
|
222
|
+
if (state.disposed || record.physicalSettled) return;
|
|
223
|
+
if (!record.observation) {
|
|
224
|
+
applySettlement(record, settlement, cause);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const late = !record.inLedger || record.epoch !== epoch;
|
|
228
|
+
const outOfOrder = settlement === "committed" && (late ? state.committedRevision > record.revision : highestCompletedRevision > record.revision);
|
|
229
|
+
applySettlement(record, settlement, cause);
|
|
230
|
+
record.observation?.finish(outOfOrder ? "out-of-order" : late ? settlement === "failed" ? "late-failed" : settlement === "committed" ? "late-committed" : "abandoned" : settlement);
|
|
231
|
+
};
|
|
200
232
|
const createFullPayload = (snapshot) => {
|
|
201
233
|
const payload = {};
|
|
202
234
|
const snapshotKeys = new Set(Object.keys(snapshot));
|
|
@@ -227,19 +259,22 @@ function createSetDataCommitTracker(options) {
|
|
|
227
259
|
tail = record;
|
|
228
260
|
state.dispatchedSnapshot = update.snapshot;
|
|
229
261
|
for (const key of Object.keys(update.payload)) knownHostTopKeys.add(key.split(".", 1)[0]);
|
|
262
|
+
record.observation = options.observe?.(update, revision);
|
|
230
263
|
const settle = (settlement, cause) => {
|
|
231
264
|
settleRecord(record, settlement, cause);
|
|
232
265
|
};
|
|
233
266
|
const hostPayload = cloneSnapshotValue(update.payload);
|
|
234
267
|
if (typeof options.adapter.__wevu_dispatchSetData === "function") try {
|
|
235
|
-
options.adapter.__wevu_dispatchSetData(hostPayload, settle);
|
|
268
|
+
options.adapter.__wevu_dispatchSetData(hostPayload, settle, record.observation?.physical);
|
|
236
269
|
} catch (cause) {
|
|
237
270
|
settle("failed", cause);
|
|
238
271
|
}
|
|
239
272
|
else observeSetDataCompletion({
|
|
240
273
|
invoke: () => options.adapter.setData?.(hostPayload),
|
|
241
274
|
completion: "return",
|
|
242
|
-
settle
|
|
275
|
+
settle,
|
|
276
|
+
payload: hostPayload,
|
|
277
|
+
observer: options.adapter.setData ? record.observation?.physical : void 0
|
|
243
278
|
});
|
|
244
279
|
return revision;
|
|
245
280
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commitTracker.mjs","names":[],"sources":["../../../../../src/runtime/app/setData/commitTracker.ts"],"sourcesContent":["import type { MiniProgramAdapter, SetDataDebugInfo } from '../../types'\nimport { cloneSnapshotValue } from './snapshot'\n\nexport type SetDataSnapshot = Record<string, unknown>\nexport type SetDataPayload = Record<string, unknown>\nexport type SetDataMode = 'diff' | 'patch'\nexport type SetDataRevisionKind = 'delta' | 'full'\nexport type SetDataAdapterSettlement = 'committed' | 'failed' | 'abandoned'\n\nexport type SetDataAdapterSettler = (\n settlement: SetDataAdapterSettlement,\n cause?: unknown,\n) => void\n\nexport interface CommitAwareSetDataAdapter extends MiniProgramAdapter {\n __wevu_dispatchSetData?: (\n payload: SetDataPayload,\n settle: SetDataAdapterSettler,\n ) => void\n __wevu_reportSetDataError?: (error: Error) => void\n __wevu_disposeSetData?: () => void\n}\n\nexport interface PreparedSetDataUpdate {\n mode: SetDataMode\n kind: SetDataRevisionKind\n reason: SetDataDebugInfo['reason']\n snapshot: SetDataSnapshot\n payload: SetDataPayload\n pendingPatchKeys: number\n}\n\nexport interface SetDataCommitFailure {\n kind: 'adapter' | 'out-of-order'\n revision: number\n committedRevision: number\n mode: SetDataMode\n cause: unknown\n error: Error\n payloadKeys: number\n pendingPatchKeys: number\n}\n\nexport interface SetDataCommitState {\n preparedSnapshot: SetDataSnapshot\n dispatchedSnapshot: SetDataSnapshot\n committedSnapshot: SetDataSnapshot\n revision: number\n committedRevision: number\n failedRevision: number | undefined\n needsFullSnapshot: boolean\n commitPromise: Promise<void>\n disposed: boolean\n}\n\nexport interface SetDataCommitTracker {\n readonly state: SetDataCommitState\n dispatch: (update: PreparedSetDataUpdate) => number\n createFullPayload: (snapshot: SetDataSnapshot) => SetDataPayload\n dispose: () => void\n}\n\ntype RevisionStatus = 'dispatched' | 'succeeded' | 'failed' | 'abandoned'\n\ninterface RevisionRecord {\n revision: number\n epoch: number\n mode: SetDataMode\n kind: SetDataRevisionKind\n snapshot: SetDataSnapshot\n payloadKeys: number\n pendingPatchKeys: number\n status: RevisionStatus\n physicalSettled: boolean\n inLedger: boolean\n next: RevisionRecord | undefined\n commitPromise?: Promise<void>\n resolveCommit?: () => void\n}\n\nconst resolvedCommitPromise = Promise.resolve()\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return Boolean(\n value\n && (typeof value === 'object' || typeof value === 'function')\n && typeof (value as PromiseLike<unknown>).then === 'function',\n )\n}\n\nfunction formatCommitFailureCause(cause: unknown): string {\n try {\n return cause instanceof Error ? cause.message : String(cause)\n }\n catch {\n return '<unprintable cause>'\n }\n}\n\nfunction createCommitError(\n kind: SetDataCommitFailure['kind'],\n record: RevisionRecord,\n cause: unknown,\n) {\n const causeMessage = formatCommitFailureCause(cause)\n const label = kind === 'adapter' ? 'adapter failure' : 'out-of-order completion'\n const error = new Error(\n `[wevu] setData commit failed (${label}, revision=${record.revision}, mode=${record.mode}, kind=${record.kind}): ${causeMessage}`,\n )\n ;(error as Error & { cause?: unknown }).cause = cause\n return error\n}\n\nexport function observeSetDataCompletion(options: {\n invoke: (callback: () => void) => unknown\n completion: 'return' | 'callback'\n settle: SetDataAdapterSettler\n}): void {\n let settled = false\n let invoking = true\n let callbackCalled = false\n let returnIsAuthoritative = false\n const settleOnce: SetDataAdapterSettler = (settlement, cause) => {\n if (settled) {\n return\n }\n settled = true\n options.settle(settlement, cause)\n }\n const callback = () => {\n if (invoking) {\n callbackCalled = true\n return\n }\n if (returnIsAuthoritative) {\n return\n }\n if (options.completion === 'callback') {\n settleOnce('committed')\n }\n }\n\n try {\n const result = options.invoke(callback)\n const resultIsThenable = isThenable(result)\n returnIsAuthoritative = resultIsThenable\n invoking = false\n if (resultIsThenable) {\n result.then(\n () => settleOnce('committed'),\n cause => settleOnce('failed', cause),\n )\n return\n }\n if (options.completion === 'return' || callbackCalled) {\n settleOnce('committed')\n }\n }\n catch (cause) {\n invoking = false\n settleOnce('failed', cause)\n }\n}\n\nexport function createSetDataCommitTracker(options: {\n initialSnapshot?: SetDataSnapshot\n adapter: CommitAwareSetDataAdapter\n onFailure: (failure: SetDataCommitFailure) => void\n}): SetDataCommitTracker {\n const initialSnapshot = options.initialSnapshot ? cloneSnapshotValue(options.initialSnapshot) : {}\n const knownHostTopKeys = new Set(Object.keys(initialSnapshot))\n let epoch = 0\n let highestCompletedRevision = 0\n let head: RevisionRecord | undefined\n let tail: RevisionRecord | undefined\n\n function ensureCommitBarrier(record: RevisionRecord) {\n if (!record.inLedger) {\n return resolvedCommitPromise\n }\n if (!record.commitPromise) {\n record.commitPromise = new Promise<void>((resolve) => {\n record.resolveCommit = resolve\n })\n }\n return record.commitPromise\n }\n\n const state: SetDataCommitState = {\n preparedSnapshot: initialSnapshot,\n dispatchedSnapshot: initialSnapshot,\n committedSnapshot: initialSnapshot,\n revision: 0,\n committedRevision: 0,\n failedRevision: undefined,\n needsFullSnapshot: false,\n get commitPromise() {\n return tail ? ensureCommitBarrier(tail) : resolvedCommitPromise\n },\n disposed: false,\n }\n\n const reportFailure = (\n kind: SetDataCommitFailure['kind'],\n record: RevisionRecord,\n cause: unknown,\n ) => {\n const error = createCommitError(kind, record, cause)\n try {\n options.onFailure({\n kind,\n revision: record.revision,\n committedRevision: state.committedRevision,\n mode: record.mode,\n cause,\n error,\n payloadKeys: record.payloadKeys,\n pendingPatchKeys: record.pendingPatchKeys,\n })\n }\n catch {\n // 错误上报不得反向破坏提交状态机。\n }\n }\n\n const resolveRecord = (record: RevisionRecord) => {\n record.resolveCommit?.()\n record.resolveCommit = undefined\n }\n\n const removePrefixThrough = (last: RevisionRecord) => {\n let current = head\n while (current) {\n const next = current.next\n current.inLedger = false\n current.next = undefined\n resolveRecord(current)\n if (current === last) {\n head = next\n if (!head) {\n tail = undefined\n }\n return\n }\n current = next\n }\n }\n\n const invalidateLedger = () => {\n let current = head\n while (current) {\n const next = current.next\n current.inLedger = false\n current.next = undefined\n if (!current.physicalSettled) {\n current.status = 'abandoned'\n }\n resolveRecord(current)\n current = next\n }\n head = undefined\n tail = undefined\n epoch += 1\n highestCompletedRevision = state.committedRevision\n }\n\n const armRecovery = () => {\n state.needsFullSnapshot = true\n }\n\n const failLineage = (\n kind: SetDataCommitFailure['kind'],\n record: RevisionRecord,\n cause: unknown,\n ) => {\n record.status = 'failed'\n state.failedRevision = record.revision\n armRecovery()\n invalidateLedger()\n reportFailure(kind, record, cause)\n }\n\n const drainSucceededPrefix = () => {\n while (head?.status === 'succeeded') {\n const record = head\n state.committedSnapshot = record.snapshot\n state.committedRevision = record.revision\n head = record.next\n record.inLedger = false\n record.next = undefined\n resolveRecord(record)\n }\n if (!head) {\n tail = undefined\n }\n }\n\n const commitFullCheckpoint = (record: RevisionRecord) => {\n state.committedSnapshot = record.snapshot\n state.committedRevision = record.revision\n state.failedRevision = undefined\n state.needsFullSnapshot = false\n removePrefixThrough(record)\n drainSucceededPrefix()\n }\n\n const handleLateSettlement = (\n record: RevisionRecord,\n settlement: SetDataAdapterSettlement,\n cause: unknown,\n ) => {\n if (settlement === 'failed') {\n reportFailure('adapter', record, cause)\n return\n }\n if (settlement === 'committed' && state.committedRevision > record.revision) {\n if (head) {\n invalidateLedger()\n }\n armRecovery()\n reportFailure(\n 'out-of-order',\n record,\n `revision ${record.revision} completed after committed revision ${state.committedRevision}`,\n )\n }\n }\n\n const settleRecord = (\n record: RevisionRecord,\n settlement: SetDataAdapterSettlement,\n cause?: unknown,\n ) => {\n if (state.disposed || record.physicalSettled) {\n return\n }\n record.physicalSettled = true\n\n if (!record.inLedger || record.epoch !== epoch) {\n handleLateSettlement(record, settlement, cause)\n return\n }\n\n if (settlement === 'abandoned') {\n record.status = 'abandoned'\n armRecovery()\n invalidateLedger()\n return\n }\n if (settlement === 'failed') {\n failLineage('adapter', record, cause)\n return\n }\n\n record.status = 'succeeded'\n if (highestCompletedRevision > record.revision) {\n failLineage(\n 'out-of-order',\n record,\n `revision ${record.revision} completed after revision ${highestCompletedRevision}`,\n )\n return\n }\n highestCompletedRevision = record.revision\n\n if (record.kind === 'full') {\n commitFullCheckpoint(record)\n return\n }\n drainSucceededPrefix()\n }\n\n const createFullPayload = (snapshot: SetDataSnapshot): SetDataPayload => {\n const payload: SetDataPayload = {}\n const snapshotKeys = new Set(Object.keys(snapshot))\n for (const [key, value] of Object.entries(snapshot)) {\n payload[key] = value === undefined ? null : value\n }\n for (const key of knownHostTopKeys) {\n if (!snapshotKeys.has(key)) {\n payload[key] = null\n }\n }\n return payload\n }\n\n const dispatch = (update: PreparedSetDataUpdate) => {\n if (state.disposed) {\n return state.revision\n }\n\n const revision = state.revision + 1\n state.revision = revision\n state.preparedSnapshot = update.snapshot\n const record: RevisionRecord = {\n revision,\n epoch,\n mode: update.mode,\n kind: update.kind,\n snapshot: update.snapshot,\n payloadKeys: Object.keys(update.payload).length,\n pendingPatchKeys: update.pendingPatchKeys,\n status: 'dispatched',\n physicalSettled: false,\n inLedger: true,\n next: undefined,\n }\n if (tail) {\n tail.next = record\n }\n else {\n head = record\n }\n tail = record\n state.dispatchedSnapshot = update.snapshot\n for (const key of Object.keys(update.payload)) {\n knownHostTopKeys.add(key.split('.', 1)[0]!)\n }\n\n const settle: SetDataAdapterSettler = (settlement, cause) => {\n settleRecord(record, settlement, cause)\n }\n // 宿主会保留对象并在后续路径更新时原地修改,载荷不能与序列化缓存及快照共享引用。\n const hostPayload = cloneSnapshotValue(update.payload)\n if (typeof options.adapter.__wevu_dispatchSetData === 'function') {\n try {\n options.adapter.__wevu_dispatchSetData(hostPayload, settle)\n }\n catch (cause) {\n settle('failed', cause)\n }\n }\n else {\n observeSetDataCompletion({\n invoke: () => options.adapter.setData?.(hostPayload),\n completion: 'return',\n settle,\n })\n }\n return revision\n }\n\n const dispose = () => {\n if (state.disposed) {\n return\n }\n state.disposed = true\n invalidateLedger()\n }\n\n return {\n state,\n dispatch,\n createFullPayload,\n dispose,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"commitTracker.mjs","names":[],"sources":["../../../../../src/runtime/app/setData/commitTracker.ts"],"sourcesContent":["import type { MiniProgramAdapter, SetDataDebugInfo } from '../../types'\nimport type { PhysicalSetDataObserver, SetDataRevisionObservation } from './observation'\nimport { observePhysicalDispatch } from './observation'\nimport { cloneSnapshotValue } from './snapshot'\n\nexport type SetDataSnapshot = Record<string, unknown>\nexport type SetDataPayload = Record<string, unknown>\nexport type SetDataMode = 'diff' | 'patch'\nexport type SetDataRevisionKind = 'delta' | 'full'\nexport type SetDataAdapterSettlement = 'committed' | 'failed' | 'abandoned'\n\nexport type SetDataAdapterSettler = (\n settlement: SetDataAdapterSettlement,\n cause?: unknown,\n) => void\n\nexport interface CommitAwareSetDataAdapter extends MiniProgramAdapter {\n __wevu_dispatchSetData?: (\n payload: SetDataPayload,\n settle: SetDataAdapterSettler,\n observer?: PhysicalSetDataObserver,\n ) => void\n __wevu_reportSetDataError?: (error: Error) => void\n __wevu_disposeSetData?: () => void\n}\n\nexport interface PreparedSetDataUpdate {\n mode: SetDataMode\n kind: SetDataRevisionKind\n reason: SetDataDebugInfo['reason']\n snapshot: SetDataSnapshot\n payload: SetDataPayload\n pendingPatchKeys: number\n}\n\nexport interface SetDataCommitFailure {\n kind: 'adapter' | 'out-of-order'\n revision: number\n committedRevision: number\n mode: SetDataMode\n cause: unknown\n error: Error\n payloadKeys: number\n pendingPatchKeys: number\n}\n\nexport interface SetDataCommitState {\n preparedSnapshot: SetDataSnapshot\n dispatchedSnapshot: SetDataSnapshot\n committedSnapshot: SetDataSnapshot\n revision: number\n committedRevision: number\n failedRevision: number | undefined\n needsFullSnapshot: boolean\n commitPromise: Promise<void>\n disposed: boolean\n}\n\nexport interface SetDataCommitTracker {\n readonly state: SetDataCommitState\n dispatch: (update: PreparedSetDataUpdate) => number\n createFullPayload: (snapshot: SetDataSnapshot) => SetDataPayload\n dispose: () => void\n}\n\ntype RevisionStatus = 'dispatched' | 'succeeded' | 'failed' | 'abandoned'\n\ninterface RevisionRecord {\n revision: number\n epoch: number\n mode: SetDataMode\n kind: SetDataRevisionKind\n snapshot: SetDataSnapshot\n payloadKeys: number\n pendingPatchKeys: number\n status: RevisionStatus\n physicalSettled: boolean\n inLedger: boolean\n next: RevisionRecord | undefined\n commitPromise?: Promise<void>\n observation?: SetDataRevisionObservation\n resolveCommit?: () => void\n}\n\nconst resolvedCommitPromise = Promise.resolve()\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return Boolean(\n value\n && (typeof value === 'object' || typeof value === 'function')\n && typeof (value as PromiseLike<unknown>).then === 'function',\n )\n}\n\nfunction formatCommitFailureCause(cause: unknown): string {\n try {\n return cause instanceof Error ? cause.message : String(cause)\n }\n catch {\n return '<unprintable cause>'\n }\n}\n\nfunction createCommitError(\n kind: SetDataCommitFailure['kind'],\n record: RevisionRecord,\n cause: unknown,\n) {\n const causeMessage = formatCommitFailureCause(cause)\n const label = kind === 'adapter' ? 'adapter failure' : 'out-of-order completion'\n const error = new Error(\n `[wevu] setData commit failed (${label}, revision=${record.revision}, mode=${record.mode}, kind=${record.kind}): ${causeMessage}`,\n )\n ;(error as Error & { cause?: unknown }).cause = cause\n return error\n}\n\nexport function observeSetDataCompletion(options: {\n invoke: (callback: () => void) => unknown\n completion: 'return' | 'callback'\n settle: SetDataAdapterSettler\n observer?: PhysicalSetDataObserver\n payload?: SetDataPayload\n}): void {\n let settled = false\n let invoking = true\n let callbackCalled = false\n let observedReturn = false\n let returnIsAuthoritative = false\n let boundary: Parameters<PhysicalSetDataObserver['complete']>[0] = options.completion\n const settleOnce: SetDataAdapterSettler = (settlement, cause) => {\n if (settled) {\n return\n }\n settled = true\n options.observer?.complete(boundary)\n options.settle(settlement, cause)\n }\n const callback = () => {\n if (invoking) {\n callbackCalled = true\n return\n }\n if (returnIsAuthoritative) {\n return\n }\n if (options.completion === 'callback') {\n settleOnce('committed')\n }\n }\n\n try {\n if (options.observer && options.payload) {\n observePhysicalDispatch(options.observer, options.payload)\n }\n const result = options.invoke(callback)\n const resultIsThenable = isThenable(result)\n returnIsAuthoritative = resultIsThenable\n invoking = false\n if (options.observer && !observedReturn) {\n observedReturn = true\n options.observer.returned(Date.now())\n }\n if (resultIsThenable) {\n boundary = 'promise'\n result.then(\n () => settleOnce('committed'),\n cause => settleOnce('failed', cause),\n )\n return\n }\n if (options.completion === 'return' || callbackCalled) {\n settleOnce('committed')\n }\n }\n catch (cause) {\n boundary = 'throw'\n invoking = false\n if (options.observer && !observedReturn) {\n observedReturn = true\n options.observer.returned(Date.now())\n }\n settleOnce('failed', cause)\n }\n}\n\nexport function createSetDataCommitTracker(options: {\n initialSnapshot?: SetDataSnapshot\n adapter: CommitAwareSetDataAdapter\n onFailure: (failure: SetDataCommitFailure) => void\n observe?: (update: PreparedSetDataUpdate, revision: number) => SetDataRevisionObservation | undefined\n}): SetDataCommitTracker {\n const initialSnapshot = options.initialSnapshot ? cloneSnapshotValue(options.initialSnapshot) : {}\n const knownHostTopKeys = new Set(Object.keys(initialSnapshot))\n let epoch = 0\n let highestCompletedRevision = 0\n let head: RevisionRecord | undefined\n let tail: RevisionRecord | undefined\n\n function ensureCommitBarrier(record: RevisionRecord) {\n if (!record.inLedger) {\n return resolvedCommitPromise\n }\n if (!record.commitPromise) {\n record.commitPromise = new Promise<void>((resolve) => {\n record.resolveCommit = resolve\n })\n }\n return record.commitPromise\n }\n\n const state: SetDataCommitState = {\n preparedSnapshot: initialSnapshot,\n dispatchedSnapshot: initialSnapshot,\n committedSnapshot: initialSnapshot,\n revision: 0,\n committedRevision: 0,\n failedRevision: undefined,\n needsFullSnapshot: false,\n get commitPromise() {\n return tail ? ensureCommitBarrier(tail) : resolvedCommitPromise\n },\n disposed: false,\n }\n\n const reportFailure = (\n kind: SetDataCommitFailure['kind'],\n record: RevisionRecord,\n cause: unknown,\n ) => {\n const error = createCommitError(kind, record, cause)\n try {\n options.onFailure({\n kind,\n revision: record.revision,\n committedRevision: state.committedRevision,\n mode: record.mode,\n cause,\n error,\n payloadKeys: record.payloadKeys,\n pendingPatchKeys: record.pendingPatchKeys,\n })\n }\n catch {\n // 错误上报不得反向破坏提交状态机。\n }\n }\n\n const resolveRecord = (record: RevisionRecord) => {\n record.resolveCommit?.()\n record.resolveCommit = undefined\n }\n\n const removePrefixThrough = (last: RevisionRecord) => {\n let current = head\n while (current) {\n const next = current.next\n current.inLedger = false\n current.next = undefined\n resolveRecord(current)\n if (current === last) {\n head = next\n if (!head) {\n tail = undefined\n }\n return\n }\n current = next\n }\n }\n\n const invalidateLedger = () => {\n let abandonedObservations: SetDataRevisionObservation[] | undefined\n const result = state.disposed ? 'disposed' : 'abandoned'\n let current = head\n while (current) {\n const next = current.next\n current.inLedger = false\n current.next = undefined\n if (!current.physicalSettled) {\n current.status = 'abandoned'\n if (current.observation) {\n (abandonedObservations ??= []).push(current.observation)\n }\n }\n resolveRecord(current)\n current = next\n }\n head = undefined\n tail = undefined\n epoch += 1\n highestCompletedRevision = state.committedRevision\n // 先清空旧账本,再交付诊断,避免回调重入时误删新 revision。\n abandonedObservations?.forEach(observation => observation.finish(result))\n }\n\n const armRecovery = () => {\n state.needsFullSnapshot = true\n }\n\n const failLineage = (\n kind: SetDataCommitFailure['kind'],\n record: RevisionRecord,\n cause: unknown,\n ) => {\n record.status = 'failed'\n state.failedRevision = record.revision\n armRecovery()\n invalidateLedger()\n reportFailure(kind, record, cause)\n }\n\n const drainSucceededPrefix = () => {\n while (head?.status === 'succeeded') {\n const record = head\n state.committedSnapshot = record.snapshot\n state.committedRevision = record.revision\n head = record.next\n record.inLedger = false\n record.next = undefined\n resolveRecord(record)\n }\n if (!head) {\n tail = undefined\n }\n }\n\n const commitFullCheckpoint = (record: RevisionRecord) => {\n state.committedSnapshot = record.snapshot\n state.committedRevision = record.revision\n state.failedRevision = undefined\n state.needsFullSnapshot = false\n removePrefixThrough(record)\n drainSucceededPrefix()\n }\n\n const handleLateSettlement = (\n record: RevisionRecord,\n settlement: SetDataAdapterSettlement,\n cause: unknown,\n ) => {\n if (settlement === 'failed') {\n reportFailure('adapter', record, cause)\n return\n }\n if (settlement === 'committed' && state.committedRevision > record.revision) {\n if (head) {\n invalidateLedger()\n }\n armRecovery()\n reportFailure(\n 'out-of-order',\n record,\n `revision ${record.revision} completed after committed revision ${state.committedRevision}`,\n )\n }\n }\n\n const applySettlement = (\n record: RevisionRecord,\n settlement: SetDataAdapterSettlement,\n cause?: unknown,\n ) => {\n if (state.disposed || record.physicalSettled) {\n return\n }\n record.physicalSettled = true\n\n if (!record.inLedger || record.epoch !== epoch) {\n handleLateSettlement(record, settlement, cause)\n return\n }\n\n if (settlement === 'abandoned') {\n record.status = 'abandoned'\n armRecovery()\n invalidateLedger()\n return\n }\n if (settlement === 'failed') {\n failLineage('adapter', record, cause)\n return\n }\n\n record.status = 'succeeded'\n if (highestCompletedRevision > record.revision) {\n failLineage(\n 'out-of-order',\n record,\n `revision ${record.revision} completed after revision ${highestCompletedRevision}`,\n )\n return\n }\n highestCompletedRevision = record.revision\n\n if (record.kind === 'full') {\n commitFullCheckpoint(record)\n return\n }\n drainSucceededPrefix()\n }\n\n const settleRecord = (record: RevisionRecord, settlement: SetDataAdapterSettlement, cause?: unknown) => {\n if (state.disposed || record.physicalSettled) {\n return\n }\n if (!record.observation) {\n applySettlement(record, settlement, cause)\n return\n }\n const late = !record.inLedger || record.epoch !== epoch\n const outOfOrder = settlement === 'committed' && (late\n ? state.committedRevision > record.revision\n : highestCompletedRevision > record.revision)\n applySettlement(record, settlement, cause)\n record.observation?.finish(outOfOrder\n ? 'out-of-order'\n : late\n ? settlement === 'failed' ? 'late-failed' : settlement === 'committed' ? 'late-committed' : 'abandoned'\n : settlement)\n }\n\n const createFullPayload = (snapshot: SetDataSnapshot): SetDataPayload => {\n const payload: SetDataPayload = {}\n const snapshotKeys = new Set(Object.keys(snapshot))\n for (const [key, value] of Object.entries(snapshot)) {\n payload[key] = value === undefined ? null : value\n }\n for (const key of knownHostTopKeys) {\n if (!snapshotKeys.has(key)) {\n payload[key] = null\n }\n }\n return payload\n }\n\n const dispatch = (update: PreparedSetDataUpdate) => {\n if (state.disposed) {\n return state.revision\n }\n\n const revision = state.revision + 1\n state.revision = revision\n state.preparedSnapshot = update.snapshot\n const record: RevisionRecord = {\n revision,\n epoch,\n mode: update.mode,\n kind: update.kind,\n snapshot: update.snapshot,\n payloadKeys: Object.keys(update.payload).length,\n pendingPatchKeys: update.pendingPatchKeys,\n status: 'dispatched',\n physicalSettled: false,\n inLedger: true,\n next: undefined,\n }\n if (tail) {\n tail.next = record\n }\n else {\n head = record\n }\n tail = record\n state.dispatchedSnapshot = update.snapshot\n for (const key of Object.keys(update.payload)) {\n knownHostTopKeys.add(key.split('.', 1)[0]!)\n }\n\n record.observation = options.observe?.(update, revision)\n const settle: SetDataAdapterSettler = (settlement, cause) => {\n settleRecord(record, settlement, cause)\n }\n // 宿主会保留对象并在后续路径更新时原地修改,载荷不能与序列化缓存及快照共享引用。\n const hostPayload = cloneSnapshotValue(update.payload)\n if (typeof options.adapter.__wevu_dispatchSetData === 'function') {\n try {\n options.adapter.__wevu_dispatchSetData(hostPayload, settle, record.observation?.physical)\n }\n catch (cause) {\n settle('failed', cause)\n }\n }\n else {\n observeSetDataCompletion({\n invoke: () => options.adapter.setData?.(hostPayload),\n completion: 'return',\n settle,\n payload: hostPayload,\n observer: options.adapter.setData ? record.observation?.physical : undefined,\n })\n }\n return revision\n }\n\n const dispose = () => {\n if (state.disposed) {\n return\n }\n state.disposed = true\n invalidateLedger()\n }\n\n return {\n state,\n dispatch,\n createFullPayload,\n dispose,\n }\n}\n"],"mappings":"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"}
|