@vesk/runtime 0.2.28 → 0.2.30
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/dist/hydrate.d.ts +11 -0
- package/dist/hydrate.d.ts.map +1 -1
- package/dist/hydrate.js +33 -0
- package/dist/index-client.d.ts +3 -1
- package/dist/index-client.d.ts.map +1 -1
- package/dist/index-client.js +2 -1
- package/dist/layout.d.ts +59 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +456 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +13 -0
- package/package.json +2 -2
package/dist/hydrate.d.ts
CHANGED
|
@@ -30,6 +30,16 @@ export interface HydrateWalker {
|
|
|
30
30
|
*/
|
|
31
31
|
retireDetached?(): void;
|
|
32
32
|
subWalker(rootEl: HTMLElement): HydrateWalker;
|
|
33
|
+
/**
|
|
34
|
+
* Transfer ownership of an explicit marker subset out of this walk: the
|
|
35
|
+
* listed markers are marked claimed here (the cursor skips them) so a
|
|
36
|
+
* scoped walker built over the same comments owns them exclusively.
|
|
37
|
+
* Used by the layout slot contract (`layout.ts`), which scopes page
|
|
38
|
+
* claims to SSR slot boundaries instead of sharing the positional cursor
|
|
39
|
+
* with nav/footer claims. Optional — walkers that cannot transfer leave
|
|
40
|
+
* the markers in place and the caller falls back to the shared walk.
|
|
41
|
+
*/
|
|
42
|
+
takeMarkers?(comments: Comment[]): void;
|
|
33
43
|
/**
|
|
34
44
|
* Claim the SSR element of a keyed list item whose `data-vsk-key` matches
|
|
35
45
|
* `key`. Consumes the item's root marker and stamps the element, but leaves
|
|
@@ -79,6 +89,7 @@ export type HydrationMismatchHandler = (issue: HydrationIssue) => void;
|
|
|
79
89
|
export declare function setHydrateStrict(enabled: boolean): void;
|
|
80
90
|
export declare function isHydrateStrict(): boolean;
|
|
81
91
|
export declare function onHydrationMismatch(handler: HydrationMismatchHandler | null): void;
|
|
92
|
+
export declare function reportHydrationIssue(issue: HydrationIssue): void;
|
|
82
93
|
/**
|
|
83
94
|
* Structured audit of the most recent full hydration pass over `container`.
|
|
84
95
|
* Counts unclaimed `<!--vsk-->` markers (SSR regions the client never
|
package/dist/hydrate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"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"}
|
package/dist/hydrate.js
CHANGED
|
@@ -62,6 +62,16 @@ export function isHydrateStrict() {
|
|
|
62
62
|
export function onHydrationMismatch(handler) {
|
|
63
63
|
__mismatchHandler = handler;
|
|
64
64
|
}
|
|
65
|
+
export function reportHydrationIssue(issue) {
|
|
66
|
+
if (!__mismatchHandler)
|
|
67
|
+
return;
|
|
68
|
+
try {
|
|
69
|
+
__mismatchHandler(issue);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Telemetry must never break rendering.
|
|
73
|
+
}
|
|
74
|
+
}
|
|
65
75
|
function devWarn(message) {
|
|
66
76
|
if (__hydrateDevMode && typeof console !== 'undefined') {
|
|
67
77
|
console.warn('[vesk-hydrate] ' + message);
|
|
@@ -613,6 +623,25 @@ class WalkerEngine {
|
|
|
613
623
|
this.idx = this.markers.length;
|
|
614
624
|
return new WalkerEngine(rootEl, owned.map((m) => m.comment));
|
|
615
625
|
}
|
|
626
|
+
// Ownership transfer for an explicit marker subset (layout slot contract).
|
|
627
|
+
// The listed markers are marked claimed here without advancing the cursor:
|
|
628
|
+
// positional claims skip them, and a scoped walker built over the same
|
|
629
|
+
// comments owns them exclusively. Exactly one engine owns each marker.
|
|
630
|
+
takeMarkers(comments) {
|
|
631
|
+
let owned;
|
|
632
|
+
try {
|
|
633
|
+
owned = new Set(comments);
|
|
634
|
+
}
|
|
635
|
+
catch {
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
if (owned.size === 0)
|
|
639
|
+
return;
|
|
640
|
+
for (const tm of this.markers) {
|
|
641
|
+
if (tm.state !== 'claimed' && owned.has(tm.comment))
|
|
642
|
+
tm.state = 'claimed';
|
|
643
|
+
}
|
|
644
|
+
}
|
|
616
645
|
// Retire every unclaimed marker in the whole walk that points at `el`.
|
|
617
646
|
// Used after a cross-position adopt (relocate): the adopted node moves to
|
|
618
647
|
// the cursor, so alias markers stacked at its old station would otherwise
|
|
@@ -764,6 +793,10 @@ export function createHydrateChildWalker(parentEl) {
|
|
|
764
793
|
retireDetached() {
|
|
765
794
|
// Child-walkers hold no marker list; nothing to sweep.
|
|
766
795
|
},
|
|
796
|
+
takeMarkers(_comments) {
|
|
797
|
+
// Child-walkers hold no marker list; nothing to transfer. The
|
|
798
|
+
// layout slot contract falls back to the shared walk.
|
|
799
|
+
},
|
|
767
800
|
};
|
|
768
801
|
}
|
|
769
802
|
export function hydrate(container, componentFn, props) {
|
package/dist/index-client.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { track, get, set, untrack, peek_tracked as peek, derived, flush_sync as flushSync, tick, schedule_update, queue_microtask, active_block, set_active_block, set_active_component, is_mutating_allowed, tracking, teardown, run_block, run_teardown, create_component_ctx, push_component, pop_component, with_block, with_scope, scope, safe_scope, set_tracking, set_active_reaction, is_block_dirty, destroy_non_branch_children, disable_scoped_flush, on_destroy } from '@vesk/runtime/src/ripple-runtime';
|
|
2
2
|
export { effect, user_effect, block, branch, root, render, pre_effect, destroy_block, destroy_block_children, pause_block, resume_block, is_destroyed, unlink_block, create_try_block, boundary_fn_running_block } from '@vesk/runtime/src/ripple-blocks';
|
|
3
|
-
export { hydrate, hydrateViewport, hydrateIdle, hydrateOnInteraction, needsHydration, hydrationCount, createHydrateWalker, collectVskMarkers, reactiveProps, hydrateInitial, assertFullyHydrated, auditHydration, setHydrateDevMode, setHydrateStrict, isHydrateStrict, onHydrationMismatch, bumpNavEpoch, isVskMarkerText, parseVskMarker } from '@vesk/runtime/src/hydrate';
|
|
3
|
+
export { hydrate, hydrateViewport, hydrateIdle, hydrateOnInteraction, needsHydration, hydrationCount, createHydrateWalker, collectVskMarkers, reactiveProps, hydrateInitial, assertFullyHydrated, auditHydration, setHydrateDevMode, setHydrateStrict, isHydrateStrict, onHydrationMismatch, reportHydrationIssue, bumpNavEpoch, isVskMarkerText, parseVskMarker } from '@vesk/runtime/src/hydrate';
|
|
4
|
+
export { createLayoutSlot, trackSlotContent, auditLayoutSlots, LAYOUT_SLOT_OPEN, LAYOUT_SLOT_CLOSE } from '@vesk/runtime/src/layout';
|
|
5
|
+
export type { LayoutSlot, LayoutSlotAudit, SlotIdentity } from '@vesk/runtime/src/layout';
|
|
4
6
|
export type { HydrationReport, HydrationIssue, HydrationIssueKind, HydrationMismatchHandler, DeferredHydrationOptions, IdleHydrationOptions, InteractionHydrationOptions, ViewportHydrationHandle } from '@vesk/runtime/src/hydrate';
|
|
5
7
|
export { createRouter, createFileRouter, Outlet, Link, NavLink, useNavigate, useParams, usePathname, useSearchParams, useRouter, buildRouteTree, defineRoute, Redirect, redirect, permanentRedirect, notFound, NotFoundError, ensureChunk, matchRoute } from '@vesk/runtime/src/router';
|
|
6
8
|
export { getNetworkState, watchNetwork } from '@vesk/runtime/src/network';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-client.d.ts","sourceRoot":"","sources":["../src/index-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY,IAAI,IAAI,EAAE,OAAO,EAAE,UAAU,IAAI,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACtf,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,sBAAsB,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC1P,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,oBAAoB,EAAE,cAAc,EAAE,cAAc,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,mBAAmB,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index-client.d.ts","sourceRoot":"","sources":["../src/index-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index-client.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { track, get, set, untrack, peek_tracked as peek, derived, flush_sync as flushSync, tick, schedule_update, queue_microtask, active_block, set_active_block, set_active_component, is_mutating_allowed, tracking, teardown, run_block, run_teardown, create_component_ctx, push_component, pop_component, with_block, with_scope, scope, safe_scope, set_tracking, set_active_reaction, is_block_dirty, destroy_non_branch_children, disable_scoped_flush, on_destroy } from '@vesk/runtime/src/ripple-runtime';
|
|
2
2
|
export { effect, user_effect, block, branch, root, render, pre_effect, destroy_block, destroy_block_children, pause_block, resume_block, is_destroyed, unlink_block, create_try_block, boundary_fn_running_block } from '@vesk/runtime/src/ripple-blocks';
|
|
3
|
-
export { hydrate, hydrateViewport, hydrateIdle, hydrateOnInteraction, needsHydration, hydrationCount, createHydrateWalker, collectVskMarkers, reactiveProps, hydrateInitial, assertFullyHydrated, auditHydration, setHydrateDevMode, setHydrateStrict, isHydrateStrict, onHydrationMismatch, bumpNavEpoch, isVskMarkerText, parseVskMarker } from '@vesk/runtime/src/hydrate';
|
|
3
|
+
export { hydrate, hydrateViewport, hydrateIdle, hydrateOnInteraction, needsHydration, hydrationCount, createHydrateWalker, collectVskMarkers, reactiveProps, hydrateInitial, assertFullyHydrated, auditHydration, setHydrateDevMode, setHydrateStrict, isHydrateStrict, onHydrationMismatch, reportHydrationIssue, bumpNavEpoch, isVskMarkerText, parseVskMarker } from '@vesk/runtime/src/hydrate';
|
|
4
|
+
export { createLayoutSlot, trackSlotContent, auditLayoutSlots, LAYOUT_SLOT_OPEN, LAYOUT_SLOT_CLOSE } from '@vesk/runtime/src/layout';
|
|
4
5
|
export { createRouter, createFileRouter, Outlet, Link, NavLink, useNavigate, useParams, usePathname, useSearchParams, useRouter, buildRouteTree, defineRoute, Redirect, redirect, permanentRedirect, notFound, NotFoundError, ensureChunk, matchRoute } from '@vesk/runtime/src/router';
|
|
5
6
|
export { getNetworkState, watchNetwork } from '@vesk/runtime/src/network';
|
|
6
7
|
export { bindValue, bindChecked, bindGroup } from '@vesk/runtime/src/bindings';
|
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { HydrateWalker } from '@vesk/runtime/src/hydrate';
|
|
2
|
+
/** SSR comment text opening a layout page-slot region. */
|
|
3
|
+
export declare const LAYOUT_SLOT_OPEN = "vsk-slot";
|
|
4
|
+
/** SSR comment text closing a layout page-slot region (also the async anchor). */
|
|
5
|
+
export declare const LAYOUT_SLOT_CLOSE = "vsk-slot-end";
|
|
6
|
+
export interface LayoutSlot {
|
|
7
|
+
/** Walker scoped to the slot's SSR markers (or the shared walker when unscopable). */
|
|
8
|
+
walker: HydrateWalker;
|
|
9
|
+
/** True when the walker is scoped to slot boundaries (not the shared cursor). */
|
|
10
|
+
scoped: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Wire an async child hydrator result: resolved slot content is inserted
|
|
13
|
+
* at its SSR position (before the slot-end boundary). Returns a promise
|
|
14
|
+
* for the layout's `__pendingChild` chain.
|
|
15
|
+
*/
|
|
16
|
+
track(promise: unknown): unknown;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Slot boundary identity. Server codegen stamps every pair with a unique id
|
|
20
|
+
* (`vsk-slot:s7` … `vsk-slot-end:s7`); pre-boundary output uses the bare texts
|
|
21
|
+
* (legacy, id `''`). Open/close are paired by EXACT id — never positionally —
|
|
22
|
+
* so nested layouts and sibling slots cannot mis-scope each other. No regex:
|
|
23
|
+
* prefix strip only.
|
|
24
|
+
*/
|
|
25
|
+
export interface SlotIdentity {
|
|
26
|
+
/** '' for legacy bare boundaries, otherwise the stamped id. */
|
|
27
|
+
id: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Anchor an async slot child: when the hydrator promise resolves, detached
|
|
31
|
+
* slot content is inserted BEFORE the slot-end boundary (its SSR position).
|
|
32
|
+
* When the boundary is gone (a navigation replaced the DOM while suspended),
|
|
33
|
+
* the late content is dropped — hydrating replaced DOM is how duplicates are
|
|
34
|
+
* born. Resolution value and errors pass through untouched.
|
|
35
|
+
*/
|
|
36
|
+
export declare function trackSlotContent(promise: unknown, anchor: Comment | null): unknown;
|
|
37
|
+
/**
|
|
38
|
+
* Build the slot scope for a layout `{children}` invocation.
|
|
39
|
+
*
|
|
40
|
+
* Transfers the whole slot range — depth-0 markers plus nested-slot
|
|
41
|
+
* interiors — out of the shared walk (`takeMarkers`), then hands back a
|
|
42
|
+
* walker scoped to the depth-0 markers only. Nav/footer claims can no longer
|
|
43
|
+
* drift into page markers and page claims can no longer steal footer markers,
|
|
44
|
+
* including across `await` suspensions (scope never depends on claim timing)
|
|
45
|
+
* and across nesting levels (an inner scope re-scans the live DOM and owns
|
|
46
|
+
* its interior exclusively). Falls back to the shared walker (legacy
|
|
47
|
+
* behavior) when boundaries are absent, unbalanced, already consumed, or the
|
|
48
|
+
* walker cannot transfer — a fallback degrades to today's semantics, never to
|
|
49
|
+
* a wrong scope.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createLayoutSlot(walker: HydrateWalker, parentEl: Element | null): LayoutSlot;
|
|
52
|
+
export interface LayoutSlotAudit {
|
|
53
|
+
ok: boolean;
|
|
54
|
+
unbalanced: number;
|
|
55
|
+
leftoverInSlot: number;
|
|
56
|
+
}
|
|
57
|
+
/** Verify slot boundary balance and slot-region claim completeness. */
|
|
58
|
+
export declare function auditLayoutSlots(container: HTMLElement): LayoutSlotAudit;
|
|
59
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAqC/D,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAC3C,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD,MAAM,WAAW,UAAU;IAC1B,sFAAsF;IACtF,MAAM,EAAE,aAAa,CAAC;IACtB,iFAAiF;IACjF,MAAM,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;CACjC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC5B,+DAA+D;IAC/D,EAAE,EAAE,MAAM,CAAC;CACX;AAyOD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAuBlF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,OAAO,GAAG,IAAI,GACtB,UAAU,CA4CZ;AAcD,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACvB;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,WAAW,GAAG,eAAe,CA8DxE"}
|
package/dist/layout.js
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import { createHydrateWalker, isVskMarkerText, reportHydrationIssue, } from '@vesk/runtime/src/hydrate';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Dedicated layout contract (Layout hydration ownership).
|
|
4
|
+
//
|
|
5
|
+
// A layout composes three independently-authored regions — chrome/nav, the
|
|
6
|
+
// page slot, footer — that SSR serializes as undifferentiated siblings inside
|
|
7
|
+
// one parent element. Hydrating all three off a single shared positional
|
|
8
|
+
// cursor means ANY single claim miss (a self-claiming Link in the nav, an
|
|
9
|
+
// async suspension in the page, a conditional) shifts every later claim into
|
|
10
|
+
// fresh-node fallback: fresh nodes append at region tails, so one miss twins
|
|
11
|
+
// the footer, and a late-resolving async page lands below the footer (or the
|
|
12
|
+
// page claims first and the layout stacks under it).
|
|
13
|
+
//
|
|
14
|
+
// Containment scoping (`subWalker(enclosingEl)`) is not the answer either: it
|
|
15
|
+
// bulk-transfers sibling markers rendered AFTER the slot (the footer) into
|
|
16
|
+
// the page's walk. The missing piece is boundary-delimited scoping, owned
|
|
17
|
+
// here:
|
|
18
|
+
//
|
|
19
|
+
// * SSR wraps every `{props.children}` region in `<!--vsk-slot-->` …
|
|
20
|
+
// `<!--vsk-slot-end-->` (server codegen). The texts deliberately lack the
|
|
21
|
+
// `vsk:` prefix so the generic marker machinery (walkers, canary, audit)
|
|
22
|
+
// ignores them; only this module reads them.
|
|
23
|
+
// * `createLayoutSlot` transfers the slot range out of the shared walk and
|
|
24
|
+
// hands back a walker scoped to the depth-0 markers. Nav/footer claims can
|
|
25
|
+
// no longer drift into page markers and page claims can no longer steal
|
|
26
|
+
// footer markers — including across `await` suspensions, because scope no
|
|
27
|
+
// longer depends on claim timing, and across nesting (nested-slot
|
|
28
|
+
// interiors are neutralized in the ancestor walk and re-scoped by the
|
|
29
|
+
// inner layout from the live DOM).
|
|
30
|
+
// * `track` anchors async slot content: a suspending child resolves to
|
|
31
|
+
// nodes inserted BEFORE the slot-end boundary at its SSR position — never
|
|
32
|
+
// appended at the tail, never dropped. A navigation that replaced the DOM
|
|
33
|
+
// first (slot-end detached) drops the late content instead of duplicating
|
|
34
|
+
// it into the new page.
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
/** SSR comment text opening a layout page-slot region. */
|
|
37
|
+
export const LAYOUT_SLOT_OPEN = 'vsk-slot';
|
|
38
|
+
/** SSR comment text closing a layout page-slot region (also the async anchor). */
|
|
39
|
+
export const LAYOUT_SLOT_CLOSE = 'vsk-slot-end';
|
|
40
|
+
function slotIdentity(text, prefix) {
|
|
41
|
+
if (text === prefix)
|
|
42
|
+
return { id: '' };
|
|
43
|
+
if (typeof text !== 'string')
|
|
44
|
+
return null;
|
|
45
|
+
const want = prefix + ':';
|
|
46
|
+
if (text.length > want.length && text.startsWith(want))
|
|
47
|
+
return { id: text.slice(want.length) };
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
function slotOpenId(text) {
|
|
51
|
+
return slotIdentity(text, LAYOUT_SLOT_OPEN);
|
|
52
|
+
}
|
|
53
|
+
function slotCloseId(text) {
|
|
54
|
+
return slotIdentity(text, LAYOUT_SLOT_CLOSE);
|
|
55
|
+
}
|
|
56
|
+
function slotUsed(node) {
|
|
57
|
+
try {
|
|
58
|
+
return node.__vsk_slot_used === true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function markSlotUsed(node) {
|
|
65
|
+
try {
|
|
66
|
+
node.__vsk_slot_used = true;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Expando unsupported — the pair may be re-scanned, which degrades to
|
|
70
|
+
// the legacy shared-walker path, never to a wrong scope.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Locate the unconsumed slot boundary pair that are direct children of
|
|
75
|
+
* `parentEl` and collect the `vsk:` markers between them in document order.
|
|
76
|
+
*
|
|
77
|
+
* Open/close pair by EXACT boundary id (legacy bare boundaries pair
|
|
78
|
+
* positionally, as before). An id-stamped open with no same-id close — or a
|
|
79
|
+
* legacy open facing only id-stamped closes (version skew) — refuses to scope
|
|
80
|
+
* (null) rather than risk a wrong range. Nested layout slots inside the range
|
|
81
|
+
* are skipped via a depth counter, so an outer slot never captures an inner
|
|
82
|
+
* layout's page markers (each layout scopes its own pair when its slot runs).
|
|
83
|
+
* Returns null when the SSR output predates slot boundaries (legacy) or the
|
|
84
|
+
* pair is unbalanced.
|
|
85
|
+
*/
|
|
86
|
+
function findSlotRange(parentEl) {
|
|
87
|
+
let open = null;
|
|
88
|
+
let openId = null;
|
|
89
|
+
let close = null;
|
|
90
|
+
try {
|
|
91
|
+
// Walk the entire subtree of parentEl (not just direct children) so a
|
|
92
|
+
// layout whose slot lives inside a nested <main> (DocsLayout:
|
|
93
|
+
// outer <div> → <div.flex> → <main>) is still found. The old
|
|
94
|
+
// direct-children scan missed those and fell back to the shared walk
|
|
95
|
+
// (257-marker hydration drift on /docs).
|
|
96
|
+
const walker = document.createTreeWalker(parentEl, 128, {
|
|
97
|
+
acceptNode: (node) => {
|
|
98
|
+
const t = node.textContent;
|
|
99
|
+
if (slotOpenId(t) !== null || slotCloseId(t) !== null)
|
|
100
|
+
return 1;
|
|
101
|
+
return 2;
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
// Nesting depth while seeking the close: a nested slot pair inside
|
|
105
|
+
// our range must not donate its close to us. Bare boundaries
|
|
106
|
+
// (`vsk-slot` … `vsk-slot-end`) carry no id, so without depth the
|
|
107
|
+
// first inner close would prematurely end the outer range and
|
|
108
|
+
// mis-scope the page. Distinct ids pair by exact id AND depth.
|
|
109
|
+
let nest = 0;
|
|
110
|
+
while (walker.nextNode()) {
|
|
111
|
+
const c = walker.currentNode;
|
|
112
|
+
const t = c.textContent;
|
|
113
|
+
if (open === null) {
|
|
114
|
+
const id = slotOpenId(t);
|
|
115
|
+
if (id !== null && !slotUsed(c)) {
|
|
116
|
+
open = c;
|
|
117
|
+
openId = id;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
if (slotOpenId(t) !== null && !slotUsed(c)) {
|
|
122
|
+
nest++;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const id = slotCloseId(t);
|
|
126
|
+
if (id === null || slotUsed(c))
|
|
127
|
+
continue;
|
|
128
|
+
if (id.id === openId.id && nest === 0) {
|
|
129
|
+
// Ensure close is after open in document order and still
|
|
130
|
+
// inside parentEl (TreeWalker guarantees this, but verify
|
|
131
|
+
// via isConnected/contains for detached-navigation safety).
|
|
132
|
+
try {
|
|
133
|
+
if (!parentEl.contains?.(c))
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
catch { }
|
|
137
|
+
close = c;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
if (nest > 0)
|
|
141
|
+
nest--;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
if (!open || !close)
|
|
149
|
+
return null;
|
|
150
|
+
// Document-order walk from `open` to `close`, collecting vsk markers at
|
|
151
|
+
// nesting depth 0 for the slot walker, and every vsk marker in range for
|
|
152
|
+
// ancestor neutralization (see `SlotRange.all`). A nested `vsk-slot` …
|
|
153
|
+
// `vsk-slot-end` pair (inner layout) increments depth so its interior
|
|
154
|
+
// markers stay owned by the inner scope.
|
|
155
|
+
const markers = [];
|
|
156
|
+
const all = [];
|
|
157
|
+
let depth = 0;
|
|
158
|
+
let node = null;
|
|
159
|
+
try {
|
|
160
|
+
node = open.nextSibling;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
let guard = 0;
|
|
166
|
+
while (node !== null && node !== close && guard++ < 100000) {
|
|
167
|
+
let next = null;
|
|
168
|
+
let descend = null;
|
|
169
|
+
try {
|
|
170
|
+
const n = node;
|
|
171
|
+
next = n.nextSibling;
|
|
172
|
+
descend = n.firstChild;
|
|
173
|
+
if (n.nodeType === 8) {
|
|
174
|
+
if (slotOpenId(n.textContent) !== null) {
|
|
175
|
+
depth++;
|
|
176
|
+
}
|
|
177
|
+
else if (slotCloseId(n.textContent) !== null) {
|
|
178
|
+
if (depth === 0)
|
|
179
|
+
break; // unbalanced: a close with no open — stop, don't over-capture
|
|
180
|
+
depth--;
|
|
181
|
+
}
|
|
182
|
+
else if (isVskMarkerText(n.textContent)) {
|
|
183
|
+
all.push(n);
|
|
184
|
+
// Depth-0 only: nested `vsk-slot` interiors stay owned by
|
|
185
|
+
// the inner layout's own scope (see the nested test in
|
|
186
|
+
// layout.test.ts). The ancestor walk is neutralized for
|
|
187
|
+
// the whole range via `all` + `takeMarkers` regardless.
|
|
188
|
+
if (depth === 0)
|
|
189
|
+
markers.push(n);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
// Preorder: descend first, else advance; climb past exhausted parents.
|
|
197
|
+
if (descend !== null && descend !== undefined) {
|
|
198
|
+
node = descend;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
let cur = node;
|
|
202
|
+
let nxt = next;
|
|
203
|
+
while (nxt === null || nxt === undefined) {
|
|
204
|
+
let parent = null;
|
|
205
|
+
try {
|
|
206
|
+
parent = cur.parentNode;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
if (parent === null || parent === undefined || parent === parentEl)
|
|
212
|
+
break;
|
|
213
|
+
if (parent === close) {
|
|
214
|
+
nxt = null;
|
|
215
|
+
cur = null;
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
nxt = parent.nextSibling;
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
cur = parent;
|
|
225
|
+
}
|
|
226
|
+
if (cur === null)
|
|
227
|
+
break;
|
|
228
|
+
node = nxt;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (node !== close)
|
|
232
|
+
return null; // never reached the close — unbalanced, refuse to scope
|
|
233
|
+
markSlotUsed(open);
|
|
234
|
+
markSlotUsed(close);
|
|
235
|
+
return { markers, all, end: close };
|
|
236
|
+
}
|
|
237
|
+
function insertDetachedSlotContent(value, anchor) {
|
|
238
|
+
let parent = null;
|
|
239
|
+
try {
|
|
240
|
+
parent = anchor.parentNode;
|
|
241
|
+
if (!parent)
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const nodes = [];
|
|
248
|
+
if (value && typeof value === 'object') {
|
|
249
|
+
const v = value;
|
|
250
|
+
if (v.nodeType === 11 || v.nodeType === 1)
|
|
251
|
+
nodes.push(v);
|
|
252
|
+
else if (typeof v.length === 'number') {
|
|
253
|
+
for (let i = 0; i < v.length; i++) {
|
|
254
|
+
const n = v[i];
|
|
255
|
+
if (n && (n.nodeType === 11 || n.nodeType === 1))
|
|
256
|
+
nodes.push(n);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
else
|
|
263
|
+
return;
|
|
264
|
+
for (const n of nodes) {
|
|
265
|
+
if (n === anchor)
|
|
266
|
+
continue;
|
|
267
|
+
let attached = null;
|
|
268
|
+
try {
|
|
269
|
+
attached = n.parentNode;
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
// Only place detached content. Attached nodes were claimed in place —
|
|
275
|
+
// moving them would reorder live DOM on a hunch.
|
|
276
|
+
if (attached !== null && attached !== undefined)
|
|
277
|
+
continue;
|
|
278
|
+
try {
|
|
279
|
+
parent.insertBefore(n, anchor);
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
// A failed insert must not strand the render; the audit reports it.
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Anchor an async slot child: when the hydrator promise resolves, detached
|
|
288
|
+
* slot content is inserted BEFORE the slot-end boundary (its SSR position).
|
|
289
|
+
* When the boundary is gone (a navigation replaced the DOM while suspended),
|
|
290
|
+
* the late content is dropped — hydrating replaced DOM is how duplicates are
|
|
291
|
+
* born. Resolution value and errors pass through untouched.
|
|
292
|
+
*/
|
|
293
|
+
export function trackSlotContent(promise, anchor) {
|
|
294
|
+
if (!promise || typeof promise.then !== 'function' || !anchor)
|
|
295
|
+
return promise;
|
|
296
|
+
return promise.then((value) => {
|
|
297
|
+
let live = false;
|
|
298
|
+
try {
|
|
299
|
+
live = !!anchor.parentNode && anchor.isConnected !== false;
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
live = false;
|
|
303
|
+
}
|
|
304
|
+
if (live)
|
|
305
|
+
insertDetachedSlotContent(value, anchor);
|
|
306
|
+
else {
|
|
307
|
+
reportHydrationIssue({
|
|
308
|
+
kind: 'leftover-marker',
|
|
309
|
+
detail: 'async layout slot resolved after its SSR boundary detached (navigation replaced the DOM); late slot content dropped instead of duplicated.',
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
return value;
|
|
313
|
+
}, (error) => {
|
|
314
|
+
throw error;
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Build the slot scope for a layout `{children}` invocation.
|
|
319
|
+
*
|
|
320
|
+
* Transfers the whole slot range — depth-0 markers plus nested-slot
|
|
321
|
+
* interiors — out of the shared walk (`takeMarkers`), then hands back a
|
|
322
|
+
* walker scoped to the depth-0 markers only. Nav/footer claims can no longer
|
|
323
|
+
* drift into page markers and page claims can no longer steal footer markers,
|
|
324
|
+
* including across `await` suspensions (scope never depends on claim timing)
|
|
325
|
+
* and across nesting levels (an inner scope re-scans the live DOM and owns
|
|
326
|
+
* its interior exclusively). Falls back to the shared walker (legacy
|
|
327
|
+
* behavior) when boundaries are absent, unbalanced, already consumed, or the
|
|
328
|
+
* walker cannot transfer — a fallback degrades to today's semantics, never to
|
|
329
|
+
* a wrong scope.
|
|
330
|
+
*/
|
|
331
|
+
export function createLayoutSlot(walker, parentEl) {
|
|
332
|
+
const fallback = {
|
|
333
|
+
walker,
|
|
334
|
+
scoped: false,
|
|
335
|
+
track: (promise) => trackSlotContent(promise, null),
|
|
336
|
+
};
|
|
337
|
+
if (!walker || !parentEl)
|
|
338
|
+
return fallback;
|
|
339
|
+
let range = null;
|
|
340
|
+
try {
|
|
341
|
+
range = findSlotRange(parentEl);
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
return fallback;
|
|
345
|
+
}
|
|
346
|
+
if (!range) {
|
|
347
|
+
reportHydrationIssue({
|
|
348
|
+
kind: 'untyped-marker',
|
|
349
|
+
detail: 'layout slot has no SSR slot boundaries (legacy output or unbalanced markers); hydrating the page on the shared walker — ordering is best-effort.',
|
|
350
|
+
});
|
|
351
|
+
return fallback;
|
|
352
|
+
}
|
|
353
|
+
if (typeof walker.takeMarkers !== 'function') {
|
|
354
|
+
reportHydrationIssue({
|
|
355
|
+
kind: 'untyped-marker',
|
|
356
|
+
detail: 'layout slot walker cannot transfer markers; hydrating the page on the shared walker — ordering is best-effort.',
|
|
357
|
+
});
|
|
358
|
+
return { walker, scoped: false, track: (promise) => trackSlotContent(promise, range.end) };
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
walker.takeMarkers(range.all);
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
return fallback;
|
|
365
|
+
}
|
|
366
|
+
let slotWalker;
|
|
367
|
+
try {
|
|
368
|
+
slotWalker = createHydrateWalker(parentEl, range.markers);
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
return fallback;
|
|
372
|
+
}
|
|
373
|
+
const end = range.end;
|
|
374
|
+
return {
|
|
375
|
+
walker: slotWalker,
|
|
376
|
+
scoped: true,
|
|
377
|
+
track: (promise) => trackSlotContent(promise, end),
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
// ---------------------------------------------------------------------------
|
|
381
|
+
// Strict slot audit: every slot boundary pair must be balanced, and no `vsk:`
|
|
382
|
+
// marker may survive inside a slot range after hydration — a leftover there is
|
|
383
|
+
// page content the client never claimed (the twin/duplication surface).
|
|
384
|
+
// Runs from the router after the layout chain hydrates (full strategy only;
|
|
385
|
+
// deferred strategies hydrate the slot later by design).
|
|
386
|
+
// ---------------------------------------------------------------------------
|
|
387
|
+
const _SHOW_COMMENT = 128;
|
|
388
|
+
const _FILTER_ACCEPT = 1;
|
|
389
|
+
const _FILTER_SKIP = 2;
|
|
390
|
+
/** Verify slot boundary balance and slot-region claim completeness. */
|
|
391
|
+
export function auditLayoutSlots(container) {
|
|
392
|
+
let unbalanced = 0;
|
|
393
|
+
let leftoverInSlot = 0;
|
|
394
|
+
try {
|
|
395
|
+
const walker = document.createTreeWalker(container, _SHOW_COMMENT, {
|
|
396
|
+
acceptNode: (node) => {
|
|
397
|
+
const t = node.textContent;
|
|
398
|
+
if (slotOpenId(t) !== null || slotCloseId(t) !== null || isVskMarkerText(t))
|
|
399
|
+
return _FILTER_ACCEPT;
|
|
400
|
+
return _FILTER_SKIP;
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
// Open-id stack: id-stamped pairs must close in LIFO order with the
|
|
404
|
+
// exact id; legacy bare boundaries pair blindly (as before). Any id
|
|
405
|
+
// mismatch names the diverging slot instead of silently mis-scoping.
|
|
406
|
+
const stack = [];
|
|
407
|
+
while (walker.nextNode()) {
|
|
408
|
+
const c = walker.currentNode;
|
|
409
|
+
const t = c.textContent;
|
|
410
|
+
const open = slotOpenId(t);
|
|
411
|
+
if (open !== null) {
|
|
412
|
+
stack.push(open.id);
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const close = slotCloseId(t);
|
|
416
|
+
if (close !== null) {
|
|
417
|
+
if (stack.length === 0) {
|
|
418
|
+
unbalanced++;
|
|
419
|
+
reportHydrationIssue({
|
|
420
|
+
kind: 'marker-skew',
|
|
421
|
+
detail: 'layout slot close without a matching open — SSR/client slot structure diverges; slot content may misorder.',
|
|
422
|
+
});
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
const top = stack.pop();
|
|
426
|
+
if (top !== '' && close.id !== '' && top !== close.id) {
|
|
427
|
+
unbalanced++;
|
|
428
|
+
reportHydrationIssue({
|
|
429
|
+
kind: 'marker-skew',
|
|
430
|
+
detail: `layout slot id mismatch: open "${top}" closed by "${close.id}" — SSR/client slot structure diverges; slot content may misorder.`,
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
if (stack.length > 0 && isVskMarkerText(t))
|
|
436
|
+
leftoverInSlot++;
|
|
437
|
+
}
|
|
438
|
+
if (stack.length > 0) {
|
|
439
|
+
unbalanced++;
|
|
440
|
+
reportHydrationIssue({
|
|
441
|
+
kind: 'marker-skew',
|
|
442
|
+
detail: 'layout slot open without a matching close — SSR/client slot structure diverges; slot content may misorder.',
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
if (leftoverInSlot > 0) {
|
|
446
|
+
reportHydrationIssue({
|
|
447
|
+
kind: 'leftover-marker',
|
|
448
|
+
detail: `${leftoverInSlot} hydration marker(s) survived inside a layout slot region; the page rendered differently than SSR — duplication risk.`,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
// Audit must never break rendering.
|
|
454
|
+
}
|
|
455
|
+
return { ok: unbalanced === 0 && leftoverInSlot === 0, unbalanced, leftoverInSlot };
|
|
456
|
+
}
|
package/dist/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
|
package/dist/router.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { get, set, scope, set_active_block } from '@vesk/runtime/src/ripple-runtime';
|
|
2
2
|
import { root } from '@vesk/runtime/src/ripple-blocks';
|
|
3
3
|
import { createHydrateWalker, hydrateViewport, hydrateIdle, hydrateOnInteraction, bumpNavEpoch } from '@vesk/runtime/src/hydrate';
|
|
4
|
+
import { auditLayoutSlots } from '@vesk/runtime/src/layout';
|
|
4
5
|
import { matchRoute, flattenLayoutChain, buildTreeFromMap } from '@vesk/runtime/src/router-match';
|
|
5
6
|
import { setIsHydrating, _state, _scrollPositions, _isPopStateNavigation, setIsPopStateNavigation, setCurrentRouter, showLoadingInContainer, handleScroll, applyHead, findLoadingComponent, findErrorComponent, findNotFoundComponent, findOfflineComponent, findNetworkComponent, getCurrentRouter, Outlet, Link, NavLink, useNavigate, useParams, usePathname, useSearchParams, useRouter, Redirect, redirect, permanentRedirect, NotFoundError, notFound, } from '@vesk/runtime/src/router-components';
|
|
6
7
|
import { getNetworkState, watchNetwork } from '@vesk/runtime/src/network';
|
|
@@ -1137,6 +1138,18 @@ async function hydrateInitial(router, match, container, strategy) {
|
|
|
1137
1138
|
}
|
|
1138
1139
|
const walker = createHydrateWalker(container);
|
|
1139
1140
|
await runInBlockWindow(() => renderLayoutChain(0)(walker));
|
|
1141
|
+
// Strict slot audit: with boundary-delimited slot walkers, any marker
|
|
1142
|
+
// surviving inside a slot region (or an unbalanced boundary pair) is a
|
|
1143
|
+
// page/layout divergence — the duplication surface. Deferred strategies
|
|
1144
|
+
// hydrate the slot later by design, so only the full strategy audits.
|
|
1145
|
+
if (!strategy || strategy === 'full') {
|
|
1146
|
+
try {
|
|
1147
|
+
auditLayoutSlots(container);
|
|
1148
|
+
}
|
|
1149
|
+
catch {
|
|
1150
|
+
// Audit must never break rendering.
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1140
1153
|
setIsHydrating(false);
|
|
1141
1154
|
}
|
|
1142
1155
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vesk/runtime",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.30",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vesk runtime — reactivity, blocks, DOM operations, hydration",
|
|
6
6
|
"main": "./dist/index-client.js",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@vesk/compiler": "^0.2.
|
|
54
|
+
"@vesk/compiler": "^0.2.30"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"typecheck": "tsc --noEmit",
|