@ogygia/core 0.11.4 → 0.12.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 +1 -1
- package/dist/KeepHost.svelte +1 -1
- package/dist/LiveHost.svelte +1 -1
- package/dist/NestedProvider.svelte +1 -1
- package/dist/Region.svelte +28 -21
- package/dist/Region.svelte.d.ts +0 -2
- package/dist/SlotBoundary.svelte +1 -1
- package/dist/compiler/bom.js +1 -1
- package/dist/compiler/browser.d.ts +1 -1
- package/dist/compiler/browser.js +1 -1
- package/dist/compiler/ctx.d.ts +1 -1
- package/dist/compiler/ctx.js +3 -3
- package/dist/compiler/{macros/dedent.d.ts → dedent.d.ts} +12 -1
- package/dist/compiler/dedent.js +43 -0
- package/dist/compiler/driver.d.ts +9 -6
- package/dist/compiler/driver.js +69 -35
- package/dist/compiler/ids.d.ts +3 -0
- package/dist/compiler/ids.js +4 -1
- package/dist/compiler/index.d.ts +3 -3
- package/dist/compiler/index.js +3 -3
- package/dist/compiler/kit.d.ts +7 -0
- package/dist/compiler/kit.js +22 -10
- package/dist/compiler/link/caps.js +59 -9
- package/dist/compiler/link/island-deps.js +225 -22
- package/dist/compiler/link/location-map.d.ts +10 -0
- package/dist/compiler/link/location-map.js +53 -0
- package/dist/compiler/link/manifest.js +5 -1
- package/dist/compiler/link/runtime-entry.d.ts +19 -2
- package/dist/compiler/link/runtime-entry.js +34 -1
- package/dist/compiler/link/server-manifest.js +43 -7
- package/dist/compiler/link/transport.js +39 -7
- package/dist/compiler/macros/source.js +2 -2
- package/dist/compiler/program.d.ts +4 -0
- package/dist/compiler/program.js +5 -1
- package/dist/compiler/region/transform.d.ts +13 -4
- package/dist/compiler/region/transform.js +15 -6
- package/dist/context.d.ts +3 -12
- package/dist/context.js +1 -16
- package/dist/hooks.d.ts +16 -0
- package/dist/hooks.js +4 -2
- package/dist/insights/page-insights.js +2 -2
- package/dist/internal.d.ts +2 -1
- package/dist/internal.js +2 -1
- package/dist/nested.d.ts +11 -0
- package/dist/nested.js +19 -0
- package/dist/ref-sink.d.ts +15 -0
- package/dist/ref-sink.js +19 -0
- package/dist/ref.d.ts +2 -2
- package/dist/ref.js +1 -11
- package/dist/runtime/beacon.js +1 -1
- package/dist/runtime/boot-link.js +4 -1
- package/dist/runtime/core.js +10 -7
- package/dist/runtime/entry-locations.d.ts +10 -3
- package/dist/runtime/entry-locations.js +132 -21
- package/dist/runtime/full.js +5 -1
- package/dist/runtime/hydrate-core.d.ts +4 -4
- package/dist/runtime/hydrate-core.js +8 -5
- package/dist/runtime/morph.d.ts +7 -0
- package/dist/runtime/morph.js +21 -15
- package/dist/runtime/nav-handle.d.ts +3 -0
- package/dist/runtime/nav-handle.js +12 -5
- package/dist/runtime/ownership.d.ts +10 -1
- package/dist/runtime/ownership.js +19 -1
- package/dist/runtime/reconcile.d.ts +5 -2
- package/dist/runtime/reconcile.js +52 -16
- package/dist/runtime/region-endpoint-url.js +1 -0
- package/dist/runtime/region-ids.js +2 -2
- package/dist/runtime/remote-seeds.js +14 -3
- package/dist/runtime/router-nav.js +15 -0
- package/dist/runtime/router.js +3 -0
- package/dist/runtime/seeds.d.ts +10 -5
- package/dist/runtime/seeds.js +16 -12
- package/dist/runtime/slots.d.ts +24 -2
- package/dist/runtime/slots.js +2 -0
- package/dist/runtime/wire-classes.d.ts +2 -0
- package/dist/runtime/wire-classes.js +10 -1
- package/dist/runtime/wire-format.d.ts +4 -1
- package/dist/runtime/wire-format.js +6 -1
- package/dist/seed-ref-reviver.d.ts +24 -0
- package/dist/seed-ref-reviver.js +44 -0
- package/dist/seed-refs.d.ts +2 -16
- package/dist/seed-refs.js +1 -33
- package/dist/server/document-tail.d.ts +3 -2
- package/dist/server/document-tail.js +4 -3
- package/dist/server/entry-location.js +11 -8
- package/dist/server/props-wire.js +4 -3
- package/dist/server/signing-key.d.ts +10 -2
- package/dist/server/signing-key.js +49 -15
- package/dist/vite/index.js +5 -4
- package/dist/vite/kit-dirs.js +1 -1
- package/package.json +3 -3
- package/dist/compiler/link/entry-shim.d.ts +0 -4
- package/dist/compiler/link/entry-shim.js +0 -29
- package/dist/compiler/macros/dedent.js +0 -36
package/dist/runtime/core.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { frameAddress } from "../frame.js";
|
|
2
2
|
import { kit_hydrates_page } from "./kit-boot.js";
|
|
3
3
|
import { init_shadow_registries, parse_region_html, restore_adopt_sheets, restore_markup } from "./parse-html.js";
|
|
4
|
-
import { wire_classes_for } from "./wire-classes.js";
|
|
5
4
|
import { mark_region_changed, region_changed, unwatch_region, watch_region } from "./drift-watch.js";
|
|
6
5
|
import { runtime_session } from "./session.js";
|
|
7
6
|
import { RegionAnswerRefused, capability_expired, deny_of, is_allowed_region_endpoint, is_document_answer, is_redirected_answer, is_same_origin_response, island_module_url, renewal_url } from "./region-endpoint-url.js";
|
|
8
|
-
import { import_entry, island_entry_of, on_entry_fallback, pin_region_urls } from "./entry-locations.js";
|
|
7
|
+
import { import_entry, island_entry_of, on_entry_fallback, pin_build_map, pin_region_urls } from "./entry-locations.js";
|
|
9
8
|
import { is_awake, is_deferred, is_frozen, ours_on_kit_document, phase2_hydrate_schedule, region_hydrate_schedule, region_schedule } from "./region-attrs.js";
|
|
10
9
|
import { slots } from "./slots.js";
|
|
11
10
|
import { KEEP_FALLBACK_HTML } from "../keep-fallback-marker.js";
|
|
12
11
|
import { PAGE_FACTS_SELECTOR } from "../page-facts-script.js";
|
|
13
|
-
import { NAV_HANDLE_KEY, mpa_nav, publish_nav } from "./nav-handle.js";
|
|
14
12
|
import { link_boot } from "./boot-link.js";
|
|
15
13
|
import { background_start, hydrate_settled, hydrate_started, hydrate_turn, register_region, unregister_region, yield_task } from "./schedule.js";
|
|
16
14
|
import { once_visible } from "./observe.js";
|
|
@@ -24,6 +22,7 @@ import { on_svelte_warning, set_hydrating, tap_svelte_warnings } from "./svelte-
|
|
|
24
22
|
import { emit } from "../events/bus.js";
|
|
25
23
|
import { ingest_server_events, install_window_sink } from "../events/sinks.js";
|
|
26
24
|
import { CLIENT_PLUGINS, boot_client_plugins, client_region_mount, client_region_unmount } from "./client-plugins.js";
|
|
25
|
+
import { FRAMES } from "virtual:ogygia/runtime-flags";
|
|
27
26
|
// src/runtime/core.ts
|
|
28
27
|
const DEVTOOLS = typeof __OGYGIA_DEVTOOLS__ !== "undefined" ? __OGYGIA_DEVTOOLS__ : false;
|
|
29
28
|
const BEACON = typeof __OGYGIA_BEACON__ !== "undefined" ? __OGYGIA_BEACON__ : true;
|
|
@@ -95,7 +94,7 @@ const ON_DEMAND_EVENTS = [
|
|
|
95
94
|
const ON_DEMAND_SELECTOR = "ogygia-region[render=\"defer\"][when=\"interaction\"]";
|
|
96
95
|
/**
|
|
97
96
|
* ON-DEMAND holes, delegated: ONE set of capture listeners on the document for every armed hole
|
|
98
|
-
* (five listeners per hole used to be five hundred on a page of
|
|
97
|
+
* (five listeners per hole used to be five hundred on a page of nav-menus). Intent lands anywhere
|
|
99
98
|
* inside a hole; the nearest ARMED hole above the target fires once and is forgotten.
|
|
100
99
|
*/
|
|
101
100
|
const on_demand_armed = /* @__PURE__ */ new Map();
|
|
@@ -353,7 +352,7 @@ var OgygiaRegion = class OgygiaRegion extends HTMLElement {
|
|
|
353
352
|
connected_regions.add(this);
|
|
354
353
|
pin_region_urls(this);
|
|
355
354
|
if (this.hasAttribute("live")) return;
|
|
356
|
-
if (this.#minted_endpoint === null && is_deferred(this)) {
|
|
355
|
+
if (FRAMES && this.#minted_endpoint === null && is_deferred(this)) {
|
|
357
356
|
const minted = this.getAttribute("endpoint");
|
|
358
357
|
if (minted) this.#minted_endpoint = minted;
|
|
359
358
|
else {
|
|
@@ -427,6 +426,7 @@ var OgygiaRegion = class OgygiaRegion extends HTMLElement {
|
|
|
427
426
|
* nothing left to warm.
|
|
428
427
|
*/
|
|
429
428
|
#prefetch_html() {
|
|
429
|
+
if (!FRAMES) return;
|
|
430
430
|
if (this.#done || this.#fetching || !this.isConnected) return;
|
|
431
431
|
const endpoint = this.#endpoint();
|
|
432
432
|
if (!endpoint || !is_allowed_region_endpoint(endpoint)) return;
|
|
@@ -592,6 +592,7 @@ var OgygiaRegion = class OgygiaRegion extends HTMLElement {
|
|
|
592
592
|
* island), schedule phase-2 hydrate — coalescing matching schedules to immediate load.
|
|
593
593
|
*/
|
|
594
594
|
async #server() {
|
|
595
|
+
if (!FRAMES) return;
|
|
595
596
|
const endpoint = this.#endpoint();
|
|
596
597
|
if (endpoint && !this.#frame_unsub) {
|
|
597
598
|
const address = this.#frame_address = frameAddress(endpoint);
|
|
@@ -718,6 +719,7 @@ var OgygiaRegion = class OgygiaRegion extends HTMLElement {
|
|
|
718
719
|
* not (the endpoint answers `cache-control: private, max-age=30`, and stale is the whole point).
|
|
719
720
|
*/
|
|
720
721
|
async #fetch_html(opts = {}) {
|
|
722
|
+
if (!FRAMES) return;
|
|
721
723
|
if (this.#fetching || this.#done && !opts.revalidate) return;
|
|
722
724
|
const endpoint = this.#endpoint();
|
|
723
725
|
if (!endpoint) return;
|
|
@@ -879,7 +881,7 @@ var OgygiaRegion = class OgygiaRegion extends HTMLElement {
|
|
|
879
881
|
[mod, core] = await Promise.all([
|
|
880
882
|
load_island(entry, cls()),
|
|
881
883
|
hydrate_core(),
|
|
882
|
-
|
|
884
|
+
slots.wire_classes?.(this)
|
|
883
885
|
]);
|
|
884
886
|
} finally {
|
|
885
887
|
release();
|
|
@@ -952,6 +954,7 @@ var OgygiaRegion = class OgygiaRegion extends HTMLElement {
|
|
|
952
954
|
* - **Later tick, module changed:** unmount, swap, re-hydrate.
|
|
953
955
|
*/
|
|
954
956
|
async applyLive(desc) {
|
|
957
|
+
if (!FRAMES) return;
|
|
955
958
|
this.setAttribute("render", "defer");
|
|
956
959
|
this.setAttribute("entry", desc.module || desc.id);
|
|
957
960
|
if (desc.url) this.setAttribute("endpoint", desc.url);
|
|
@@ -1122,10 +1125,10 @@ function apply_dev_head_region_css() {
|
|
|
1122
1125
|
});
|
|
1123
1126
|
}
|
|
1124
1127
|
function boot(installers = [], client_plugins = []) {
|
|
1125
|
-
if (typeof document !== "undefined" && !(NAV_HANDLE_KEY in globalThis)) publish_nav(mpa_nav());
|
|
1126
1128
|
runtime_session.adopt_document_head();
|
|
1127
1129
|
link_boot();
|
|
1128
1130
|
for (const install of installers) install();
|
|
1131
|
+
pin_build_map();
|
|
1129
1132
|
on_entry_fallback((report) => {
|
|
1130
1133
|
if (DEVTOOLS) emit({
|
|
1131
1134
|
domain: "runtime",
|
|
@@ -11,6 +11,13 @@ export declare function on_entry_fallback(reporter: (report: EntryFallbackReport
|
|
|
11
11
|
export declare function note_entry_location(entry: string | null | undefined, src: string | null | undefined, base?: string): void;
|
|
12
12
|
/** The known location of an entry, or undefined. */
|
|
13
13
|
export declare function entry_location(entry: string, base?: string): string | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Pin the build map's address to the page that wrote it, as `pin_region_urls` pins a region's: with
|
|
16
|
+
* Kit's default `paths.relative` it is written relative to that page, and it is read lazily — after a
|
|
17
|
+
* client navigation to another depth, resolved against the new address, it named a file that is not
|
|
18
|
+
* there. The runtime calls this at boot, before any navigation.
|
|
19
|
+
*/
|
|
20
|
+
export declare function pin_build_map(): void;
|
|
14
21
|
/**
|
|
15
22
|
* PIN A REGION'S URLS TO THE PAGE THAT WROTE THEM. With Kit's default `paths.relative`, the server
|
|
16
23
|
* writes `entry` / `src` / `endpoint` relative to the page it rendered (`../../_app/immutable/…`,
|
|
@@ -26,8 +33,8 @@ export declare function pin_region_urls(el: Element, base?: string): void;
|
|
|
26
33
|
/** An island element's identity, its location noted on the way (the one read every loader uses). */
|
|
27
34
|
export declare function island_entry_of(el: Element): string | null;
|
|
28
35
|
/**
|
|
29
|
-
* Import an entry: its location when known
|
|
30
|
-
*
|
|
31
|
-
*
|
|
36
|
+
* Import an entry: its location when known (else this build's map names it, once read); failing that,
|
|
37
|
+
* or with none anywhere, the CURRENT build's location — so an island on a page that outlived its build
|
|
38
|
+
* still wakes, on the current code. `url`: what the caller resolved for the identity.
|
|
32
39
|
*/
|
|
33
40
|
export declare function import_entry<T>(entry: string, url?: string): Promise<T>;
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* fingerprint, the devtools' names). The file to import is its LOCATION — content-hashed, so an
|
|
7
7
|
* `immutable` cache never serves a stale one. The server writes it beside the identity: the region
|
|
8
8
|
* element's `src`, and the island graph's `s` map for an entry no element carries (a portable
|
|
9
|
-
* snippet's)
|
|
10
|
-
* here first: the location once one
|
|
11
|
-
*
|
|
9
|
+
* snippet's), and the build's location maps for the rest (`import_entry`). Every loader resolves
|
|
10
|
+
* through `island_module_url` (region-endpoint-url.ts), which asks here first: the location once one
|
|
11
|
+
* is known, else the identity (on the dev server, the module itself; in a build, a name, no file).
|
|
12
12
|
*/
|
|
13
13
|
/** absolute identity → absolute location */
|
|
14
14
|
const locations = /* @__PURE__ */ new Map();
|
|
@@ -43,6 +43,48 @@ function note_entry_location(entry, src, base) {
|
|
|
43
43
|
function entry_location(entry, base) {
|
|
44
44
|
return locations.size ? locations.get(absolute(entry, base)) : void 0;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* THIS BUILD'S LOCATION MAP (compiler/link/location-map.ts, the content-hashed one): every island entry's
|
|
48
|
+
* location by identity, for a load that arrives with an identity alone — a region the browser
|
|
49
|
+
* rendered, a held region from the wire, a snippet whose host carried no graph. The runtime's script
|
|
50
|
+
* names it (`data-og-locations`); it is read once, on the first such load. Content-hashed, so no
|
|
51
|
+
* cache serves it stale. It only fills gaps: a location a page wrote (a later build's, after a
|
|
52
|
+
* navigation) always wins over the map of the build the runtime came from. No map, or it failed
|
|
53
|
+
* (the dev server, a page that outlived its build): the identity is loaded, as before. A failed read
|
|
54
|
+
* is not kept: the next identity-only load asks again (a blip must not cost the page every later one).
|
|
55
|
+
*/
|
|
56
|
+
const BUILD_MAP_ATTR = "data-og-locations";
|
|
57
|
+
let build_map = null;
|
|
58
|
+
/**
|
|
59
|
+
* Pin the build map's address to the page that wrote it, as `pin_region_urls` pins a region's: with
|
|
60
|
+
* Kit's default `paths.relative` it is written relative to that page, and it is read lazily — after a
|
|
61
|
+
* client navigation to another depth, resolved against the new address, it named a file that is not
|
|
62
|
+
* there. The runtime calls this at boot, before any navigation.
|
|
63
|
+
*/
|
|
64
|
+
function pin_build_map() {
|
|
65
|
+
if (typeof document === "undefined") return;
|
|
66
|
+
const script = document.querySelector(`script[${BUILD_MAP_ATTR}]`);
|
|
67
|
+
const href = script?.getAttribute(BUILD_MAP_ATTR);
|
|
68
|
+
if (script && href) script.setAttribute(BUILD_MAP_ATTR, absolute(href));
|
|
69
|
+
}
|
|
70
|
+
function read_build_map() {
|
|
71
|
+
if (build_map) return build_map;
|
|
72
|
+
if (typeof document === "undefined") return null;
|
|
73
|
+
const href = document.querySelector(`script[${BUILD_MAP_ATTR}]`)?.getAttribute(BUILD_MAP_ATTR);
|
|
74
|
+
if (!href) return null;
|
|
75
|
+
const url = absolute(href);
|
|
76
|
+
const read = fetch(url).then((res) => res.ok ? res.json() : null).catch(() => null).then((map) => {
|
|
77
|
+
if (!map) {
|
|
78
|
+
if (build_map === read) build_map = null;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
for (const stable in map) {
|
|
82
|
+
const identity = absolute(stable, url);
|
|
83
|
+
if (!locations.has(identity)) locations.set(identity, absolute(map[stable], url));
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return build_map = read;
|
|
87
|
+
}
|
|
46
88
|
/** The region attributes that hold a URL: its identity, its location, its hole's endpoint. */
|
|
47
89
|
const REGION_URL_ATTRS = [
|
|
48
90
|
"entry",
|
|
@@ -80,32 +122,101 @@ function island_entry_of(el) {
|
|
|
80
122
|
return entry;
|
|
81
123
|
}
|
|
82
124
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
125
|
+
* THE CURRENT BUILD'S MAP (compiler/link/location-map.ts): the one file at a fixed name, in the app
|
|
126
|
+
* dir of the identities it maps (`<appDir>/ogygia.json`), so any app's is found from an identity alone.
|
|
127
|
+
* A page that outlived its build reads it when its own files are gone (or it never named a map) and
|
|
128
|
+
* wakes on the current code. Revalidated (a host serves it as any changing file; `no-cache` past one
|
|
129
|
+
* that kept it anyway), read once per document per app. Only an ogygia identity has one: the dev
|
|
130
|
+
* server's module URLs never ask.
|
|
87
131
|
*/
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return
|
|
132
|
+
const current_maps = /* @__PURE__ */ new Map();
|
|
133
|
+
/** A build's island identity (`…/<appDir>/ogygia/og-region.<id>.js`): a name, no file. */
|
|
134
|
+
function is_build_identity(entry) {
|
|
135
|
+
return absolute(entry).includes("/ogygia/og-region.");
|
|
92
136
|
}
|
|
137
|
+
/** The current map's file for an identity (`<appDir>/ogygia.json`), or null: not a build's identity. */
|
|
138
|
+
function current_map_file(identity) {
|
|
139
|
+
const dir = identity.lastIndexOf("/ogygia/og-region.");
|
|
140
|
+
return dir === -1 ? null : identity.slice(0, dir) + "/ogygia.json";
|
|
141
|
+
}
|
|
142
|
+
/** The current build's location for `entry`: null when its map has none, undefined when the map
|
|
143
|
+
* could not be read (that read is not kept: the next ask reads again). */
|
|
144
|
+
async function current_location(entry) {
|
|
145
|
+
const identity = absolute(entry);
|
|
146
|
+
const file = current_map_file(identity);
|
|
147
|
+
if (!file) return null;
|
|
148
|
+
let map = current_maps.get(file);
|
|
149
|
+
if (!map) {
|
|
150
|
+
map = fetch(file, { cache: "no-cache" }).then((res) => res.ok ? res.json() : null).catch(() => null);
|
|
151
|
+
current_maps.set(file, map);
|
|
152
|
+
}
|
|
153
|
+
const pairs = await map;
|
|
154
|
+
if (!pairs) {
|
|
155
|
+
forget_current_map(file, map);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
for (const name in pairs) if (absolute(name, file) === identity) return absolute(pairs[name], file);
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
function forget_current_map(file, map = current_maps.get(file)) {
|
|
162
|
+
if (current_maps.get(file) === map) current_maps.delete(file);
|
|
163
|
+
}
|
|
164
|
+
/** The host says this file is not there (it does not say so of a file that failed another way). */
|
|
165
|
+
function is_gone(url) {
|
|
166
|
+
return fetch(url, {
|
|
167
|
+
method: "HEAD",
|
|
168
|
+
cache: "no-store"
|
|
169
|
+
}).then((res) => res.status === 404 || res.status === 410, () => false);
|
|
170
|
+
}
|
|
171
|
+
/** How long a recovery waits before each ask of the current map: a rollover settles in seconds. */
|
|
172
|
+
const RECOVERY_WAITS = [
|
|
173
|
+
0,
|
|
174
|
+
1e3,
|
|
175
|
+
3e3,
|
|
176
|
+
9e3
|
|
177
|
+
];
|
|
93
178
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
179
|
+
* The current build's file for a build's identity whose file just failed to load. A deploy's rollover
|
|
180
|
+
* is exactly when this is asked, so an answer that cannot be the current one is asked again while it
|
|
181
|
+
* settles: a map that could not be read (a 404, a 5xx), and a map that names the very file that just
|
|
182
|
+
* failed when the host says that file is gone — an edge still answering with the old build's map. A
|
|
183
|
+
* file that failed some other way (the network, a broken module) is not asked about again.
|
|
184
|
+
*/
|
|
185
|
+
async function recover_location(entry, failed) {
|
|
186
|
+
let current;
|
|
187
|
+
for (const wait of RECOVERY_WAITS) {
|
|
188
|
+
if (wait) await new Promise((resolve) => setTimeout(resolve, wait));
|
|
189
|
+
current = await current_location(entry);
|
|
190
|
+
if (current === void 0) continue;
|
|
191
|
+
if (current !== failed || !await is_gone(failed)) break;
|
|
192
|
+
forget_current_map(current_map_file(absolute(entry)));
|
|
193
|
+
}
|
|
194
|
+
return current ?? null;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Import an entry: its location when known (else this build's map names it, once read); failing that,
|
|
198
|
+
* or with none anywhere, the CURRENT build's location — so an island on a page that outlived its build
|
|
199
|
+
* still wakes, on the current code. `url`: what the caller resolved for the identity.
|
|
97
200
|
*/
|
|
98
201
|
function import_entry(entry, url = entry_location(entry) ?? entry) {
|
|
99
|
-
|
|
202
|
+
if (entry_location(entry)) return load_entry(entry, url);
|
|
203
|
+
return (read_build_map() ?? Promise.resolve()).then(async () => {
|
|
204
|
+
const located = entry_location(entry);
|
|
205
|
+
if (located) return load_entry(entry, located);
|
|
206
|
+
return load_entry(entry, await current_location(entry) || url);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function load_entry(entry, url) {
|
|
210
|
+
return import(
|
|
100
211
|
/* @vite-ignore */
|
|
101
212
|
url
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
213
|
+
).catch(async (error) => {
|
|
214
|
+
const failed = absolute(url);
|
|
215
|
+
const current = is_build_identity(entry) ? await recover_location(entry, failed) : absolute(entry);
|
|
216
|
+
if (!current || current === failed) throw error;
|
|
106
217
|
const retry = import(
|
|
107
218
|
/* @vite-ignore */
|
|
108
|
-
|
|
219
|
+
current
|
|
109
220
|
);
|
|
110
221
|
const report = (recovered) => fallback_reporter?.({
|
|
111
222
|
entry,
|
|
@@ -116,4 +227,4 @@ function import_entry(entry, url = entry_location(entry) ?? entry) {
|
|
|
116
227
|
return retry;
|
|
117
228
|
});
|
|
118
229
|
}
|
|
119
|
-
export { entry_location, import_entry, island_entry_of, note_entry_location, on_entry_fallback, pin_region_urls };
|
|
230
|
+
export { entry_location, import_entry, island_entry_of, note_entry_location, on_entry_fallback, pin_build_map, pin_region_urls };
|
package/dist/runtime/full.js
CHANGED
|
@@ -5,13 +5,15 @@ import { install as install$2 } from "./morph.js";
|
|
|
5
5
|
import { install as install$3 } from "./interaction.js";
|
|
6
6
|
import { install as install$4 } from "./form-continuity.js";
|
|
7
7
|
import { install as install$5 } from "./router.js";
|
|
8
|
+
import { install as install$6 } from "./wire-classes.js";
|
|
9
|
+
import { install as install$7 } from "./nav-handle.js";
|
|
8
10
|
// src/runtime/full.ts
|
|
9
11
|
/**
|
|
10
12
|
* Kitchen-sink browser runtime — every BOOT-phase feature installed. The dev / no-marks entry: the
|
|
11
13
|
* ogygia compiler injects `bootDev()` (see the plugin's `virtual:ogygia-runtime`); a per-app production
|
|
12
14
|
* build instead emits a generated entry (see `vite/runtime-entry.ts`) that boots only the features it
|
|
13
15
|
* uses. Both boot through {@link ./core.js core} in the same {@link ../vite/runtime-entry.js FEATURE_ORDER}.
|
|
14
|
-
* HYDRATE-phase features (context, live, wire, remote-seeds) are never in the boot, dev included: the
|
|
16
|
+
* HYDRATE-phase features (context, live, wire, remote-seeds, page) are never in the boot, dev included: the
|
|
15
17
|
* hydrate core installs them from `virtual:ogygia/hydrate-features` (every one, in dev).
|
|
16
18
|
*
|
|
17
19
|
* Exposed as an explicit FUNCTION, not a top-level side effect: the compiler always calls it, so the
|
|
@@ -21,11 +23,13 @@ import { install as install$5 } from "./router.js";
|
|
|
21
23
|
* Idempotent via {@link ./core.js boot}. */
|
|
22
24
|
function bootDev(client_plugins = []) {
|
|
23
25
|
boot([
|
|
26
|
+
install$6,
|
|
24
27
|
install,
|
|
25
28
|
install$1,
|
|
26
29
|
install$2,
|
|
27
30
|
install$3,
|
|
28
31
|
install$4,
|
|
32
|
+
install$7,
|
|
29
33
|
install$5
|
|
30
34
|
], client_plugins);
|
|
31
35
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { seed_page_once, seed_remote_once } from "./seeds.js";
|
|
2
|
-
import { kit_page_thread } from "./kit-page-thread.svelte.js";
|
|
3
1
|
import { Component } from "svelte";
|
|
2
|
+
export declare const seed_page_once: () => void;
|
|
3
|
+
export declare const seed_remote_once: () => void;
|
|
4
|
+
export declare const kit_page_thread: () => Promise<void> | null;
|
|
4
5
|
/** A hydrated island as the element holds it: how to tear it down, and (keep / live hosts) how to
|
|
5
6
|
* push the next page's props into it. */
|
|
6
7
|
export type IslandHandle = {
|
|
@@ -97,5 +98,4 @@ export declare function hydrate_island(region: HTMLElement, entry: string, mod:
|
|
|
97
98
|
* HTML comes from svelte `render()` (both envelope layers) — same as the deferred swap path, so it
|
|
98
99
|
* is NOT wrapped in extra `[..]` hydration comments. `null` when the live feature is absent.
|
|
99
100
|
*/
|
|
100
|
-
export declare function hydrate_live(region: HTMLElement, entry: string, mod: IslandModule, props: Record<string, unknown>): IslandHandle | null;
|
|
101
|
-
export { kit_page_thread, seed_page_once, seed_remote_once };
|
|
101
|
+
export declare function hydrate_live(region: HTMLElement, entry: string, mod: IslandModule, props: Record<string, unknown>): IslandHandle | null;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { set_current_region, set_foreign_hydrate } from "../current-region.js";
|
|
2
2
|
import { capture_region_ids } from "./region-ids.js";
|
|
3
3
|
import { foreign_region_prop_revivers } from "./foreign-props.js";
|
|
4
|
-
import { SEED_REF_KEY, seed_ref_reviver } from "../seed-
|
|
5
|
-
import { parse_sidecar_text
|
|
4
|
+
import { SEED_REF_KEY, seed_ref_reviver } from "../seed-ref-reviver.js";
|
|
5
|
+
import { parse_sidecar_text } from "./wire-format.js";
|
|
6
6
|
import { is_deferred, ours_on_kit_document, region_ssr_truncated } from "./region-attrs.js";
|
|
7
7
|
import { boot_link, slots } from "./slots.js";
|
|
8
8
|
import { keep_host_classes, note_host_classes } from "./host-classes.js";
|
|
9
9
|
import { emit } from "../events/bus.js";
|
|
10
|
-
import { kit_page_thread } from "./kit-page-thread.svelte.js";
|
|
11
10
|
import { hydrate, unmount } from "svelte";
|
|
12
11
|
import NestedProvider from "../NestedProvider.svelte";
|
|
13
12
|
import { install } from "virtual:ogygia/hydrate-features";
|
|
@@ -24,6 +23,9 @@ import { install } from "virtual:ogygia/hydrate-features";
|
|
|
24
23
|
* Stateless towards the element: the element owns its handle (`IslandHandle`) and its flags; this
|
|
25
24
|
* module owns the how.
|
|
26
25
|
*/
|
|
26
|
+
const seed_page_once = () => slots.page?.seed_page_once();
|
|
27
|
+
const seed_remote_once = () => slots.remoteSeeds?.seed_once();
|
|
28
|
+
const kit_page_thread = () => slots.page?.kit_page_thread() ?? null;
|
|
27
29
|
install();
|
|
28
30
|
const kit_hydrates_page = () => boot_link().kit_hydrates_page();
|
|
29
31
|
const props_sidecar_of = (region) => boot_link().props_sidecar_of(region);
|
|
@@ -335,9 +337,10 @@ function read_region_props(region, foreign = false) {
|
|
|
335
337
|
if (!sidecar) return {};
|
|
336
338
|
const base = foreign ? foreign_region_prop_revivers() : region_prop_revivers();
|
|
337
339
|
const doc = sidecar.ownerDocument;
|
|
338
|
-
const
|
|
340
|
+
const page = slots.page;
|
|
341
|
+
const revivers = foreign || !page ? base : {
|
|
339
342
|
...base,
|
|
340
|
-
[SEED_REF_KEY]: seed_ref_reviver(() => seed_data_of(doc))
|
|
343
|
+
[SEED_REF_KEY]: seed_ref_reviver(() => page.seed_data_of(doc))
|
|
341
344
|
};
|
|
342
345
|
return parse_sidecar_text(sidecar, revivers);
|
|
343
346
|
}
|
package/dist/runtime/morph.d.ts
CHANGED
|
@@ -35,6 +35,13 @@ export declare function morph_children(parent: Element, new_nodes: ArrayLike<Nod
|
|
|
35
35
|
*/
|
|
36
36
|
export interface MorphOptions {
|
|
37
37
|
target?: "live" | "walk";
|
|
38
|
+
/**
|
|
39
|
+
* A child of the ROOT that is not the render's (the router's body reconcile: a node a script put
|
|
40
|
+
* in `<body>`, such as a portal's mount anchor; ownership.ts `server_body_child`). The morph steps
|
|
41
|
+
* over it: never matched, never moved, never removed. The render's children around it reconcile
|
|
42
|
+
* as usual. Root level only; below the root the ownership rules decide.
|
|
43
|
+
*/
|
|
44
|
+
stays?: (node: Node) => boolean;
|
|
38
45
|
}
|
|
39
46
|
/** Add + update + remove attributes so `from` matches `to` exactly. Boolean attrs are attr presence.
|
|
40
47
|
* `keep_extra` (a self-owned element, {@link is_self_owned}): add + update only — an attribute the
|
package/dist/runtime/morph.js
CHANGED
|
@@ -95,7 +95,7 @@ function morph_children(parent, new_nodes, options) {
|
|
|
95
95
|
const owner = owner_of(parent);
|
|
96
96
|
if (owner !== "walk" && owner !== "region") return;
|
|
97
97
|
}
|
|
98
|
-
reconcile(parent, new_nodes, build_id_sets(parent, new_nodes), walk);
|
|
98
|
+
reconcile(parent, new_nodes, build_id_sets(parent, new_nodes), walk, options?.stays);
|
|
99
99
|
clear_aria_hidden_over_focus(parent);
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
@@ -191,18 +191,24 @@ function reserved_for_later(sets, new_inner, cursor, idx) {
|
|
|
191
191
|
* ({@link reconcile_by_identity}). Toward Svelte's walk, positions are always the render's (the walk
|
|
192
192
|
* binds by position).
|
|
193
193
|
*/
|
|
194
|
-
function reconcile(parent, new_nodes, sets, walk) {
|
|
194
|
+
function reconcile(parent, new_nodes, sets, walk, stays) {
|
|
195
195
|
if (!walk && order_owner(parent) === "element") reconcile_by_identity(parent, new_nodes, sets);
|
|
196
|
-
else reconcile_children(parent, new_nodes, sets, walk);
|
|
196
|
+
else reconcile_children(parent, new_nodes, sets, walk, stays);
|
|
197
197
|
}
|
|
198
198
|
/**
|
|
199
199
|
* The render's sequence, by position.
|
|
200
200
|
* @param walk the {@link MorphOptions.target} is Svelte's walk (the repair), threaded unchanged down
|
|
201
201
|
* the recursion — a subtree the walk never enters is skipped.
|
|
202
|
+
* @param stays the root's children that are not the render's ({@link MorphOptions.stays}): the
|
|
203
|
+
* cursor steps over them, so they are never matched, moved or removed. Not threaded down.
|
|
202
204
|
*/
|
|
203
|
-
function reconcile_children(parent, new_nodes, sets, walk = false) {
|
|
205
|
+
function reconcile_children(parent, new_nodes, sets, walk = false, stays) {
|
|
204
206
|
const count = new_nodes.length;
|
|
205
|
-
|
|
207
|
+
const step = (n) => {
|
|
208
|
+
if (stays) while (n && stays(n)) n = n.nextSibling;
|
|
209
|
+
return n;
|
|
210
|
+
};
|
|
211
|
+
let cursor = step(parent.firstChild);
|
|
206
212
|
let idx = 0;
|
|
207
213
|
while (idx < count && cursor) {
|
|
208
214
|
const next = new_nodes[idx];
|
|
@@ -213,11 +219,11 @@ function reconcile_children(parent, new_nodes, sets, walk = false) {
|
|
|
213
219
|
if (!same_node(cursor, next)) break;
|
|
214
220
|
if (sets !== null && !id_sets_agree(sets, cursor, next)) break;
|
|
215
221
|
const here = cursor;
|
|
216
|
-
cursor = cursor.nextSibling;
|
|
222
|
+
cursor = step(cursor.nextSibling);
|
|
217
223
|
morph_same(here, next, sets, walk);
|
|
218
224
|
} else {
|
|
219
225
|
const here = cursor;
|
|
220
|
-
cursor = cursor.nextSibling;
|
|
226
|
+
cursor = step(cursor.nextSibling);
|
|
221
227
|
morph_node(here, next, sets, walk);
|
|
222
228
|
}
|
|
223
229
|
idx++;
|
|
@@ -225,7 +231,7 @@ function reconcile_children(parent, new_nodes, sets, walk = false) {
|
|
|
225
231
|
if (idx >= count) {
|
|
226
232
|
while (cursor) {
|
|
227
233
|
const gone = cursor;
|
|
228
|
-
cursor = cursor.nextSibling;
|
|
234
|
+
cursor = step(cursor.nextSibling);
|
|
229
235
|
parent.removeChild(gone);
|
|
230
236
|
}
|
|
231
237
|
return;
|
|
@@ -236,7 +242,7 @@ function reconcile_children(parent, new_nodes, sets, walk = false) {
|
|
|
236
242
|
}
|
|
237
243
|
let old_keys = null;
|
|
238
244
|
let old_inner = null;
|
|
239
|
-
for (let n = cursor; n; n = n.nextSibling) {
|
|
245
|
+
for (let n = cursor; n; n = step(n.nextSibling)) {
|
|
240
246
|
const k = key_of(n);
|
|
241
247
|
if (k !== null) (old_keys ??= /* @__PURE__ */ new Map()).set(k, n);
|
|
242
248
|
else if (sets !== null && n.nodeType === ELEMENT) {
|
|
@@ -260,7 +266,7 @@ function reconcile_children(parent, new_nodes, sets, walk = false) {
|
|
|
260
266
|
const next = new_nodes[idx];
|
|
261
267
|
if (cursor && key_of(next) === null && same_node(cursor, next)) {
|
|
262
268
|
const here = cursor;
|
|
263
|
-
cursor = cursor.nextSibling;
|
|
269
|
+
cursor = step(cursor.nextSibling);
|
|
264
270
|
morph_same(here, next, sets, walk);
|
|
265
271
|
} else parent.insertBefore(clone(next), cursor);
|
|
266
272
|
}
|
|
@@ -271,7 +277,7 @@ function reconcile_children(parent, new_nodes, sets, walk = false) {
|
|
|
271
277
|
const matched = old_keys?.get(next_key);
|
|
272
278
|
if (matched !== void 0) {
|
|
273
279
|
old_keys.delete(next_key);
|
|
274
|
-
if (matched === cursor) cursor = cursor.nextSibling;
|
|
280
|
+
if (matched === cursor) cursor = step(cursor.nextSibling);
|
|
275
281
|
else parent.insertBefore(matched, cursor);
|
|
276
282
|
morph_node(matched, next, sets, walk);
|
|
277
283
|
continue;
|
|
@@ -281,7 +287,7 @@ function reconcile_children(parent, new_nodes, sets, walk = false) {
|
|
|
281
287
|
const holder = wanted === void 0 ? null : find_holder(old_inner, wanted, next);
|
|
282
288
|
if (holder !== null) {
|
|
283
289
|
release_holder(old_inner, sets, holder);
|
|
284
|
-
if (holder === cursor) cursor = cursor.nextSibling;
|
|
290
|
+
if (holder === cursor) cursor = step(cursor.nextSibling);
|
|
285
291
|
else parent.insertBefore(holder, cursor);
|
|
286
292
|
morph_same(holder, next, sets, walk);
|
|
287
293
|
continue;
|
|
@@ -291,11 +297,11 @@ function reconcile_children(parent, new_nodes, sets, walk = false) {
|
|
|
291
297
|
while (cursor) {
|
|
292
298
|
cur_key = key_of(cursor);
|
|
293
299
|
if (cur_key === null || old_keys === null || !old_keys.has(cur_key)) break;
|
|
294
|
-
cursor = cursor.nextSibling;
|
|
300
|
+
cursor = step(cursor.nextSibling);
|
|
295
301
|
}
|
|
296
302
|
if (cursor && next_key === null && cur_key === null && same_node(cursor, next) && (old_inner === null || !reserved_for_later(sets, new_inner, cursor, idx))) {
|
|
297
303
|
const here = cursor;
|
|
298
|
-
cursor = cursor.nextSibling;
|
|
304
|
+
cursor = step(cursor.nextSibling);
|
|
299
305
|
if (old_inner !== null) release_holder(old_inner, sets, here);
|
|
300
306
|
morph_same(here, next, sets, walk);
|
|
301
307
|
continue;
|
|
@@ -304,7 +310,7 @@ function reconcile_children(parent, new_nodes, sets, walk = false) {
|
|
|
304
310
|
}
|
|
305
311
|
while (cursor) {
|
|
306
312
|
const gone = cursor;
|
|
307
|
-
cursor = cursor.nextSibling;
|
|
313
|
+
cursor = step(cursor.nextSibling);
|
|
308
314
|
parent.removeChild(gone);
|
|
309
315
|
}
|
|
310
316
|
if (old_keys) {
|
|
@@ -16,6 +16,9 @@ export type NavHandle = {
|
|
|
16
16
|
afterNavigate(fn: AfterNavigateCallback): () => void;
|
|
17
17
|
bust_page_cache(): void;
|
|
18
18
|
};
|
|
19
|
+
/** Feature entry (`mpa-nav`, boot phase): the MPA handle, first — the router's install, later in
|
|
20
|
+
* the feature order, replaces it. */
|
|
21
|
+
export declare function install(): void;
|
|
19
22
|
/** Publish the document's navigation handle (the router's replaces the MPA one). */
|
|
20
23
|
export declare function publish_nav(handle: NavHandle): void;
|
|
21
24
|
/**
|
|
@@ -13,16 +13,23 @@ import { speculate_url } from "./speculate-hint.js";
|
|
|
13
13
|
* from the global realm (the same pattern as the Kit page bridge, `Symbol.for('ogygia.kit-page')`),
|
|
14
14
|
* and `test/runtime-boot-svelte-free.test.ts` pins that no island-side module imports a boot module.
|
|
15
15
|
*
|
|
16
|
-
* Who publishes it,
|
|
16
|
+
* Who publishes it, on a document ogygia boots:
|
|
17
17
|
* - the ROUTER feature (./router.ts `install`) — the SPA router's API;
|
|
18
|
-
* - otherwise
|
|
19
|
-
* Speculation Rules hints, and `invalidateAll` is still the soft seed
|
|
20
|
-
* loaded on first use) — exactly what `router: false` apps got before.
|
|
18
|
+
* - otherwise the `mpa-nav` feature ({@link install}) publishes {@link mpa_nav}: the browser
|
|
19
|
+
* navigates, preloads become Speculation Rules hints, and `invalidateAll` is still the soft seed
|
|
20
|
+
* refresh (./router-nav.ts, loaded on first use) — exactly what `router: false` apps got before.
|
|
21
|
+
* Installed only when island code can reach the handle (the `page` mark: `$app/navigation`,
|
|
22
|
+
* `ogygia/app`, or anything the build could not follow): with none of those, nothing reads it.
|
|
21
23
|
*
|
|
22
24
|
* Island code reads it as `globalThis[Symbol.for('ogygia.nav')]` (the key is repeated there on
|
|
23
25
|
* purpose: importing {@link NAV_HANDLE_KEY} would be the very edge this module exists to avoid).
|
|
24
26
|
*/
|
|
25
27
|
const NAV_HANDLE_KEY = Symbol.for("ogygia.nav");
|
|
28
|
+
/** Feature entry (`mpa-nav`, boot phase): the MPA handle, first — the router's install, later in
|
|
29
|
+
* the feature order, replaces it. */
|
|
30
|
+
function install() {
|
|
31
|
+
if (typeof document !== "undefined" && !(NAV_HANDLE_KEY in globalThis)) publish_nav(mpa_nav());
|
|
32
|
+
}
|
|
26
33
|
/** Publish the document's navigation handle (the router's replaces the MPA one). */
|
|
27
34
|
function publish_nav(handle) {
|
|
28
35
|
globalThis[NAV_HANDLE_KEY] = handle;
|
|
@@ -68,4 +75,4 @@ function mpa_nav() {
|
|
|
68
75
|
bust_page_cache() {}
|
|
69
76
|
};
|
|
70
77
|
}
|
|
71
|
-
export { NAV_HANDLE_KEY, mpa_nav, publish_nav };
|
|
78
|
+
export { NAV_HANDLE_KEY, install, mpa_nav, publish_nav };
|
|
@@ -98,4 +98,13 @@ export declare function mark_render_made(node: Node): void;
|
|
|
98
98
|
* produces at this level (`render_tags`) is render output — a runtime does not make the render's
|
|
99
99
|
* elements. Anything else is the element's own: never matched, never removed.
|
|
100
100
|
*/
|
|
101
|
-
export declare function render_made(node: Node, render_tags: ReadonlySet<string>): boolean;
|
|
101
|
+
export declare function render_made(node: Node, render_tags: ReadonlySet<string>): boolean;
|
|
102
|
+
/** Record what the server sent `root` (`<body>`): the attribute names on `sent` (the root as the
|
|
103
|
+
* server rendered it), and `children` (the live root's nodes that are the server's) as render output. */
|
|
104
|
+
export declare function record_server_body(root: Element, sent: Element, children: Iterable<Node>): void;
|
|
105
|
+
/** The attribute names the server last sent `root`, or null for a root with no record yet (all of
|
|
106
|
+
* it is then taken to be the server's). */
|
|
107
|
+
export declare function server_body_attributes(root: Element): ReadonlySet<string> | null;
|
|
108
|
+
/** Is `node`, a child of `<body>`, the server's? Recorded, or an `<ogygia-region>`. Anything else
|
|
109
|
+
* the page's scripts put there: a navigation neither matches nor removes it. */
|
|
110
|
+
export declare function server_body_child(node: Node): boolean;
|
|
@@ -112,4 +112,22 @@ function render_made(node, render_tags) {
|
|
|
112
112
|
const name = node.localName;
|
|
113
113
|
return name === REGION || render_tags.has(name);
|
|
114
114
|
}
|
|
115
|
-
|
|
115
|
+
const NO_TAGS = /* @__PURE__ */ new Set();
|
|
116
|
+
const server_attrs = /* @__PURE__ */ new WeakMap();
|
|
117
|
+
/** Record what the server sent `root` (`<body>`): the attribute names on `sent` (the root as the
|
|
118
|
+
* server rendered it), and `children` (the live root's nodes that are the server's) as render output. */
|
|
119
|
+
function record_server_body(root, sent, children) {
|
|
120
|
+
server_attrs.set(root, new Set(Array.from(sent.attributes, (a) => a.name)));
|
|
121
|
+
for (const n of children) mark_render_made(n);
|
|
122
|
+
}
|
|
123
|
+
/** The attribute names the server last sent `root`, or null for a root with no record yet (all of
|
|
124
|
+
* it is then taken to be the server's). */
|
|
125
|
+
function server_body_attributes(root) {
|
|
126
|
+
return server_attrs.get(root) ?? null;
|
|
127
|
+
}
|
|
128
|
+
/** Is `node`, a child of `<body>`, the server's? Recorded, or an `<ogygia-region>`. Anything else
|
|
129
|
+
* the page's scripts put there: a navigation neither matches nor removes it. */
|
|
130
|
+
function server_body_child(node) {
|
|
131
|
+
return render_made(node, NO_TAGS);
|
|
132
|
+
}
|
|
133
|
+
export { BAKED_ATTR, HTML_PARENT_ATTR, OPAQUE_ATTR, REGION_RENDER_ATTRS, attributes_writer, is_declared_foreign, is_region_owned, is_self_owned, is_upgraded_ce, mark_render_made, order_owner, owner_of, record_server_body, render_made, server_body_attributes, server_body_child, slots_light_dom, walk_enters };
|
|
@@ -27,7 +27,9 @@ export declare function stamp_region_keys(root: ParentNode): void;
|
|
|
27
27
|
* here, on either document.
|
|
28
28
|
*/
|
|
29
29
|
export declare const NO_RECONCILE_SELECTOR = "[data-og-no-reconcile]";
|
|
30
|
-
export declare function reconcile_body(live: Element, next: Element, morph: (parent: Element, nodes: ArrayLike<Node
|
|
30
|
+
export declare function reconcile_body(live: Element, next: Element, morph: (parent: Element, nodes: ArrayLike<Node>, options?: {
|
|
31
|
+
stays?: (node: Node) => boolean;
|
|
32
|
+
}) => void): void;
|
|
31
33
|
/**
|
|
32
34
|
* outerSync body swap — the FALLBACK path (reconcile off, or a region trapped in a shadow root the
|
|
33
35
|
* morph can't pierce). The old code did `document.body.replaceWith(doc.body)`, which THROWS AWAY the
|
|
@@ -35,7 +37,8 @@ export declare function reconcile_body(live: Element, next: Element, morph: (par
|
|
|
35
37
|
* analytics, a scroll library) attached to `document.body`. htmx 4 boosts land the same way and use
|
|
36
38
|
* `outerSync` for exactly this reason: keep the element, sync its attributes, replace its children.
|
|
37
39
|
* So we do too — the live body node survives, only its guts change. Incoming children are moved out
|
|
38
|
-
* of the parsed document (insertion adopts them across documents).
|
|
40
|
+
* of the parsed document (insertion adopts them across documents). The page's own children (a
|
|
41
|
+
* portal's anchor) stay, as in the reconcile; the server's are replaced.
|
|
39
42
|
*/
|
|
40
43
|
export declare function swap_body(live: HTMLElement, next: HTMLElement): void;
|
|
41
44
|
export { endpoint_key, fingerprint_of, fnv1a, signature_of };
|