@ogygia/core 0.12.3 → 0.13.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/dist/LateIsland.svelte +3 -2
- package/dist/LateIslandAwait.svelte +6 -2
- package/dist/Region.svelte +22 -33
- package/dist/boundary.d.ts +0 -2
- package/dist/boundary.js +8 -6
- package/dist/compiler/debarrel/barrel.d.ts +15 -8
- package/dist/compiler/debarrel/barrel.js +92 -45
- package/dist/compiler/debarrel/plugin.js +41 -17
- package/dist/compiler/dev/dev-hmr.d.ts +3 -0
- package/dist/compiler/dev/dev-hmr.js +3 -0
- package/dist/compiler/driver.js +11 -4
- package/dist/compiler/flags.js +21 -7
- package/dist/compiler/fouc-css.js +5 -1
- package/dist/compiler/kit.js +5 -1
- package/dist/compiler/link/build-output.js +12 -3
- package/dist/compiler/macros/bake.js +18 -4
- package/dist/compiler/macros/dollar.js +6 -1
- package/dist/compiler/macros/source.js +6 -1
- package/dist/compiler/macros/store.js +10 -2
- package/dist/compiler/macros/wire.js +6 -1
- package/dist/compiler/parse/scan.js +10 -3
- package/dist/compiler/region/transform.js +188 -74
- package/dist/context-bridge.js +13 -5
- package/dist/context.d.ts +9 -0
- package/dist/context.js +30 -1
- package/dist/document.d.ts +1 -1
- package/dist/document.js +7 -1
- package/dist/early-holes-head.d.ts +5 -0
- package/dist/early-holes-head.js +20 -0
- package/dist/early-holes.d.ts +34 -0
- package/dist/early-holes.js +51 -0
- package/dist/entry-hydrate.js +9 -12
- package/dist/events/bus.js +7 -2
- package/dist/events/schema.d.ts +2 -2
- package/dist/fn-transport.js +4 -3
- package/dist/hooks.js +94 -163
- package/dist/insights/page-assets.js +11 -3
- package/dist/insights/page-insights.d.ts +0 -2
- package/dist/insights/page-insights.js +14 -10
- package/dist/insights/session-insights.js +2 -2
- package/dist/internal-instruments.d.ts +3 -1
- package/dist/internal-instruments.js +3 -1
- package/dist/internal-server.d.ts +3 -2
- package/dist/internal-server.js +3 -2
- package/dist/internal.d.ts +1 -2
- package/dist/internal.js +1 -2
- package/dist/keep-fallback.d.ts +0 -2
- package/dist/keep-fallback.js +4 -5
- package/dist/live-transport.js +3 -2
- package/dist/messages/build.d.ts +585 -0
- package/dist/messages/build.js +800 -0
- package/dist/messages/core.d.ts +464 -0
- package/dist/messages/core.js +843 -0
- package/dist/messages/define.d.ts +62 -0
- package/dist/messages/define.js +49 -0
- package/dist/messages/index.d.ts +6 -0
- package/dist/messages/index.js +6 -0
- package/dist/messages/island.d.ts +4 -0
- package/dist/messages/island.js +34 -0
- package/dist/messages/lazy.d.ts +3 -0
- package/dist/messages/lazy.js +22 -0
- package/dist/messages/prose.d.ts +15 -0
- package/dist/messages/prose.js +43 -0
- package/dist/messages/server.d.ts +142 -0
- package/dist/messages/server.js +246 -0
- package/dist/nested.d.ts +3 -0
- package/dist/nested.js +8 -1
- package/dist/plugin/css.js +14 -13
- package/dist/plugin/facts.d.ts +2 -0
- package/dist/plugin/facts.js +10 -6
- package/dist/plugin/hooks.d.ts +7 -17
- package/dist/plugin/hooks.js +32 -4
- package/dist/plugin/index.d.ts +9 -2
- package/dist/plugin/request-scope.d.ts +20 -0
- package/dist/plugin/request-scope.js +149 -0
- package/dist/plugin/server.d.ts +20 -2
- package/dist/plugin/server.js +98 -28
- package/dist/plugin/testing.d.ts +6 -0
- package/dist/plugin/testing.js +14 -2
- package/dist/policies.d.ts +21 -0
- package/dist/policies.js +66 -0
- package/dist/preference.js +6 -1
- package/dist/preload.js +6 -9
- package/dist/ref-watch.d.ts +0 -10
- package/dist/ref-watch.js +14 -1
- package/dist/ref.js +17 -5
- package/dist/region-snippet.js +9 -3
- package/dist/region.js +2 -1
- package/dist/report-thrown.d.ts +9 -0
- package/dist/report-thrown.js +15 -0
- package/dist/rules.d.ts +17 -0
- package/dist/rules.js +57 -0
- package/dist/runtime/beacon.d.ts +0 -4
- package/dist/runtime/beacon.js +58 -43
- package/dist/runtime/boot-link.js +19 -2
- package/dist/runtime/client-hooks.js +2 -1
- package/dist/runtime/concurrency.d.ts +16 -5
- package/dist/runtime/concurrency.js +123 -7
- package/dist/runtime/core.d.ts +3 -1
- package/dist/runtime/core.js +718 -384
- package/dist/runtime/devalue-lane.d.ts +13 -0
- package/dist/runtime/devalue-lane.js +49 -0
- package/dist/runtime/disclose-version.d.ts +1 -0
- package/dist/runtime/disclose-version.js +14 -0
- package/dist/runtime/early-holes.d.ts +4 -0
- package/dist/runtime/early-holes.js +40 -0
- package/dist/runtime/entry-locations.js +40 -49
- package/dist/runtime/foreign-props.d.ts +0 -7
- package/dist/runtime/foreign-props.js +2 -1
- package/dist/runtime/form-continuity.d.ts +2 -2
- package/dist/runtime/form-continuity.js +30 -8
- package/dist/runtime/frame-nav.d.ts +7 -1
- package/dist/runtime/frame-nav.js +84 -18
- package/dist/runtime/frame-store.d.ts +25 -16
- package/dist/runtime/frame-store.js +124 -98
- package/dist/runtime/frames.js +8 -4
- package/dist/runtime/hole-facts.js +6 -7
- package/dist/runtime/hole-fetch.d.ts +17 -0
- package/dist/runtime/hole-fetch.js +47 -0
- package/dist/runtime/hydrate-core.d.ts +4 -4
- package/dist/runtime/hydrate-core.js +80 -64
- package/dist/runtime/import-again.d.ts +33 -0
- package/dist/runtime/import-again.js +217 -0
- package/dist/runtime/interaction-replay.d.ts +5 -3
- package/dist/runtime/interaction-replay.js +6 -6
- package/dist/runtime/interaction.d.ts +14 -3
- package/dist/runtime/interaction.js +46 -23
- package/dist/runtime/kit-page-thread.svelte.d.ts +2 -1
- package/dist/runtime/kit-page-thread.svelte.js +44 -20
- package/dist/runtime/lakes.d.ts +1 -1
- package/dist/runtime/lakes.js +18 -5
- package/dist/runtime/live.d.ts +1 -2
- package/dist/runtime/live.js +6 -8
- package/dist/runtime/load-scheduler.d.ts +29 -18
- package/dist/runtime/load-scheduler.js +236 -136
- package/dist/runtime/nav-handle.js +25 -6
- package/dist/runtime/navigation.d.ts +24 -0
- package/dist/runtime/navigation.js +24 -0
- package/dist/runtime/ownership.d.ts +1 -1
- package/dist/runtime/page-defer.js +3 -3
- package/dist/runtime/parse-html.d.ts +15 -4
- package/dist/runtime/parse-html.js +24 -5
- package/dist/runtime/pushable-props.svelte.d.ts +21 -0
- package/dist/runtime/pushable-props.svelte.js +37 -0
- package/dist/runtime/region-endpoint-url.js +4 -6
- package/dist/runtime/region-machines.d.ts +111 -0
- package/dist/runtime/region-machines.js +97 -0
- package/dist/runtime/region-sheets.d.ts +31 -0
- package/dist/runtime/region-sheets.js +49 -0
- package/dist/runtime/restore-report.d.ts +1 -0
- package/dist/runtime/restore-report.js +36 -0
- package/dist/runtime/restore.d.ts +5 -2
- package/dist/runtime/restore.js +33 -14
- package/dist/runtime/router-nav.d.ts +32 -12
- package/dist/runtime/router-nav.js +320 -228
- package/dist/runtime/router.d.ts +83 -19
- package/dist/runtime/router.js +297 -129
- package/dist/runtime/rules.d.ts +35 -0
- package/dist/runtime/rules.js +137 -0
- package/dist/runtime/schedule.d.ts +6 -3
- package/dist/runtime/schedule.js +172 -57
- package/dist/runtime/seeds.d.ts +5 -1
- package/dist/runtime/seeds.js +11 -5
- package/dist/runtime/session.d.ts +46 -7
- package/dist/runtime/session.js +78 -10
- package/dist/runtime/slots.d.ts +53 -20
- package/dist/runtime/slots.js +2 -3
- package/dist/runtime/soft-refresh.d.ts +16 -0
- package/dist/runtime/soft-refresh.js +14 -0
- package/dist/runtime/svelte-warnings.d.ts +4 -10
- package/dist/runtime/svelte-warnings.js +7 -4
- package/dist/runtime/wire-classes.js +21 -8
- package/dist/runtime/wire-format.js +6 -3
- package/dist/script.js +8 -7
- package/dist/seed-ref-reviver.d.ts +0 -9
- package/dist/seed-ref-reviver.js +2 -1
- package/dist/seed-refs.d.ts +46 -36
- package/dist/seed-refs.js +131 -92
- package/dist/server/document-tail.d.ts +6 -0
- package/dist/server/document-tail.js +7 -1
- package/dist/server/early-holes-csp.d.ts +14 -0
- package/dist/server/early-holes-csp.js +73 -0
- package/dist/server/page-facts.d.ts +4 -1
- package/dist/server/page-facts.js +4 -1
- package/dist/server/page-seed.d.ts +2 -2
- package/dist/server/page-seed.js +104 -11
- package/dist/server/page-stream.d.ts +14 -1
- package/dist/server/page-stream.js +119 -2
- package/dist/server/personal-response.d.ts +0 -5
- package/dist/server/personal-response.js +6 -2
- package/dist/server/props-wire.js +5 -1
- package/dist/server/region-endpoint.js +10 -2
- package/dist/server/render-cache.d.ts +24 -20
- package/dist/server/render-cache.js +99 -40
- package/dist/server/render-page.js +46 -15
- package/dist/server/request-stats.d.ts +10 -8
- package/dist/server/request-stats.js +20 -12
- package/dist/server/rules.d.ts +11 -0
- package/dist/server/rules.js +64 -0
- package/dist/server/signing-key.js +31 -18
- package/dist/server/stream-regions.d.ts +14 -1
- package/dist/server/stream-regions.js +38 -2
- package/dist/shared-state.js +5 -1
- package/dist/shims/app-navigation.js +3 -2
- package/dist/shims/page-store.svelte.js +16 -2
- package/dist/source.js +7 -2
- package/dist/store-transport.js +12 -5
- package/dist/transport.js +3 -2
- package/dist/vite/index.js +17 -10
- package/dist/vite/kit-dirs.js +7 -1
- package/dist/vite/options.d.ts +2 -1
- package/dist/vite/options.js +11 -20
- package/dist/vite/package-files.js +13 -3
- package/dist/vite/paths.d.ts +2 -0
- package/dist/vite/paths.js +4 -4
- package/dist/vite/plugin-api.js +42 -14
- package/dist/vite/style-preprocess.js +10 -3
- package/package.json +8 -1
- package/dist/KeepHost.svelte +0 -19
- package/dist/KeepHost.svelte.d.ts +0 -10
- package/dist/LiveHost.svelte +0 -19
- package/dist/LiveHost.svelte.d.ts +0 -10
- package/dist/NestedProvider.svelte +0 -13
- package/dist/NestedProvider.svelte.d.ts +0 -8
- package/dist/runtime/page-cache.d.ts +0 -23
- package/dist/runtime/page-cache.js +0 -74
|
@@ -6,6 +6,7 @@ import { regionId, regionIdentity, strategyKey } from "./identity.js";
|
|
|
6
6
|
import { regionBindingVirtualId } from "../ids.js";
|
|
7
7
|
import { island_entry_source, lake_wrapper_source, make_region_binding, make_wake_island, server_wrapper_source } from "./emit.js";
|
|
8
8
|
import { blank_styles } from "../blank-styles.js";
|
|
9
|
+
import { OgygiaError, warn } from "../../messages/build.js";
|
|
9
10
|
import { parse } from "svelte/compiler";
|
|
10
11
|
import MagicString from "magic-string";
|
|
11
12
|
// src/compiler/region/transform.ts
|
|
@@ -16,7 +17,11 @@ function warn_unparsed(id, err) {
|
|
|
16
17
|
if (warned_unparsed.has(id)) return;
|
|
17
18
|
warned_unparsed.add(id);
|
|
18
19
|
const e = err;
|
|
19
|
-
|
|
20
|
+
warn("region_host_skipped", {
|
|
21
|
+
file: id,
|
|
22
|
+
reason: e.code ?? (e.message ?? "parse error").split("\n")[0].slice(0, 80),
|
|
23
|
+
at: e.start?.line ? `${e.start.line}:${(e.start.column ?? 0) + 1}` : ""
|
|
24
|
+
});
|
|
20
25
|
}
|
|
21
26
|
const REGEXP_META = /[.*+?^${}()|[\]\\]/g;
|
|
22
27
|
const PATH_SEP = /[/\\]/;
|
|
@@ -93,10 +98,10 @@ function line_col(src, offset) {
|
|
|
93
98
|
}
|
|
94
99
|
/** Once per key for the process — the ssr AND client passes both transform the same host. */
|
|
95
100
|
const store_warned = /* @__PURE__ */ new Set();
|
|
96
|
-
function warn_once(key,
|
|
101
|
+
function warn_once(key, say) {
|
|
97
102
|
if (store_warned.has(key)) return;
|
|
98
103
|
store_warned.add(key);
|
|
99
|
-
|
|
104
|
+
say();
|
|
100
105
|
}
|
|
101
106
|
const KNOWN_STRATEGIES = /* @__PURE__ */ new Set([
|
|
102
107
|
"load",
|
|
@@ -158,14 +163,17 @@ function normalize_import_keys_uncached(overrides) {
|
|
|
158
163
|
["render", render],
|
|
159
164
|
["preset", preset],
|
|
160
165
|
["region", region]
|
|
161
|
-
]) if (!name || !JS_IDENT.test(name)) throw new
|
|
166
|
+
]) if (!name || !JS_IDENT.test(name)) throw new OgygiaError("import_key_invalid", {
|
|
167
|
+
role,
|
|
168
|
+
got: String(JSON.stringify(overrides?.[role]))
|
|
169
|
+
});
|
|
162
170
|
if ((/* @__PURE__ */ new Set([
|
|
163
171
|
wake,
|
|
164
172
|
fetch,
|
|
165
173
|
render,
|
|
166
174
|
preset,
|
|
167
175
|
region
|
|
168
|
-
])).size !== 5) throw new
|
|
176
|
+
])).size !== 5) throw new OgygiaError("import_keys_not_distinct");
|
|
169
177
|
return {
|
|
170
178
|
wake,
|
|
171
179
|
fetch,
|
|
@@ -339,7 +347,10 @@ function parse_ts_as_region_options(arg, fail, regionKey, wakeKey, renderKey, fe
|
|
|
339
347
|
*/
|
|
340
348
|
function normalize_region_value(raw, where, regionKey = "region") {
|
|
341
349
|
if ((raw ?? "").trim() === "raw") return;
|
|
342
|
-
throw new
|
|
350
|
+
throw new OgygiaError("region_value_not_raw", {
|
|
351
|
+
host: where,
|
|
352
|
+
key: regionKey
|
|
353
|
+
});
|
|
343
354
|
}
|
|
344
355
|
/**
|
|
345
356
|
* Validate a `wake:` schedule value on a held import (a `.ts` registry / remote). Accepts the wake
|
|
@@ -349,7 +360,11 @@ function normalize_region_value(raw, where, regionKey = "region") {
|
|
|
349
360
|
function normalize_hydrate_value(raw, where, wakeKey = "wake") {
|
|
350
361
|
const v = (raw ?? "").trim();
|
|
351
362
|
if (HYDRATE_STRATEGIES.has(v) || is_media_query(v)) return v;
|
|
352
|
-
throw new
|
|
363
|
+
throw new OgygiaError("wake_strategy_unknown", {
|
|
364
|
+
host: where,
|
|
365
|
+
key: wakeKey,
|
|
366
|
+
value: v
|
|
367
|
+
});
|
|
353
368
|
}
|
|
354
369
|
/** Reconstruct an import declaration without its `with { ... }` attributes clause. */
|
|
355
370
|
function clean_import_text(source, node) {
|
|
@@ -613,7 +628,10 @@ function assert_swr_lake_crossable(node, err) {
|
|
|
613
628
|
*/
|
|
614
629
|
function resolve_component_path(spec, host_id, ctx) {
|
|
615
630
|
if (typeof spec !== "string" || !spec.trim()) return null;
|
|
616
|
-
if (spec.startsWith(".") && VIRTUAL_HOST_RE.test(host_id)) throw new
|
|
631
|
+
if (spec.startsWith(".") && VIRTUAL_HOST_RE.test(host_id)) throw new OgygiaError("generated_module_relative_import", {
|
|
632
|
+
host: host_id,
|
|
633
|
+
specifier: spec
|
|
634
|
+
});
|
|
617
635
|
if (spec === "$lib" || spec.startsWith("$lib/")) return ctx.pathModule.join(ctx.libDir, spec === "$lib" ? "" : spec.slice(5));
|
|
618
636
|
if (spec.startsWith(".")) return ctx.pathModule.resolve(ctx.pathModule.dirname(host_id), spec);
|
|
619
637
|
return spec;
|
|
@@ -736,21 +754,19 @@ var FileCompilation = class {
|
|
|
736
754
|
if (early) return early.done;
|
|
737
755
|
return this.#lower();
|
|
738
756
|
}
|
|
739
|
-
/**
|
|
740
|
-
|
|
741
|
-
|
|
757
|
+
/** Every name the host's code references outside its imports and the `skip`ped instance
|
|
758
|
+
* statements: Identifier names, Component names and each dotted prefix of one (`<Ui.Card>`
|
|
759
|
+
* references `Ui`). ONE walk answers every "is `local` used?" question — asking per import walked
|
|
760
|
+
* the whole file once per island, quadratic in the island count. Pure over the AST. */
|
|
761
|
+
#referenced_names(skip) {
|
|
762
|
+
const names = /* @__PURE__ */ new Set();
|
|
742
763
|
const walk = (node) => {
|
|
743
|
-
if (
|
|
744
|
-
if (node.type === "Identifier"
|
|
745
|
-
|
|
746
|
-
return;
|
|
747
|
-
}
|
|
748
|
-
if (node.type === "Component") {
|
|
764
|
+
if (!node || typeof node !== "object") return;
|
|
765
|
+
if (node.type === "Identifier") names.add(node.name);
|
|
766
|
+
else if (node.type === "Component") {
|
|
749
767
|
const n = node.name || "";
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
return;
|
|
753
|
-
}
|
|
768
|
+
names.add(n);
|
|
769
|
+
for (let i = n.indexOf("."); i !== -1; i = n.indexOf(".", i + 1)) names.add(n.slice(0, i));
|
|
754
770
|
}
|
|
755
771
|
for (const k of Object.keys(node)) {
|
|
756
772
|
if (k === "start" || k === "end" || k === "loc") continue;
|
|
@@ -759,21 +775,15 @@ var FileCompilation = class {
|
|
|
759
775
|
else if (v && typeof v === "object" && typeof v.type === "string") walk(v);
|
|
760
776
|
}
|
|
761
777
|
};
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
778
|
+
for (const n of this.#instance_body) if (n.type !== "ImportDeclaration" && !skip?.has(n)) walk(n);
|
|
779
|
+
for (const n of this.#module_body) if (n.type !== "ImportDeclaration") walk(n);
|
|
780
|
+
for (const n of this.#ast.fragment?.nodes ?? []) walk(n);
|
|
781
|
+
return names;
|
|
765
782
|
}
|
|
783
|
+
#used_names;
|
|
766
784
|
/** Is a marked import's `local` used anywhere but its own import (else it is dead, strip it)? */
|
|
767
785
|
#marked_import_referenced(local) {
|
|
768
|
-
|
|
769
|
-
if (n.type === "ImportDeclaration") continue;
|
|
770
|
-
if (this.#ast_refs_local(n, local)) return true;
|
|
771
|
-
}
|
|
772
|
-
for (const n of this.#module_body) {
|
|
773
|
-
if (n.type === "ImportDeclaration") continue;
|
|
774
|
-
if (this.#ast_refs_local(n, local)) return true;
|
|
775
|
-
}
|
|
776
|
-
return this.#ast_refs_local(this.#ast.fragment?.nodes ?? [], local);
|
|
786
|
+
return (this.#used_names ??= this.#referenced_names()).has(local);
|
|
777
787
|
}
|
|
778
788
|
#resolve_region_mark(inline, fail) {
|
|
779
789
|
const import_keys = this.#import_keys;
|
|
@@ -841,7 +851,14 @@ var FileCompilation = class {
|
|
|
841
851
|
const said = from_preset ? `preset '${from_preset}'` : "this import";
|
|
842
852
|
if (render_mode === "deferred" && wake_val != null) {
|
|
843
853
|
if (fetch_val != null) throw fail(`${said} times a \`${import_keys.render}: 'deferred'\` hole twice, with \`${import_keys.fetch}: '${fetch_val}'\` and \`${import_keys.wake}: '${wake_val}'\`. Keep \`${import_keys.fetch}\`: it says when a hole's HTML arrives.`);
|
|
844
|
-
warn_once(`deferred-wake:${rel_host}:${said}:${wake_val}`,
|
|
854
|
+
warn_once(`deferred-wake:${rel_host}:${said}:${wake_val}`, () => warn("hole_wake_deprecated", {
|
|
855
|
+
host: rel_host,
|
|
856
|
+
said,
|
|
857
|
+
render_key: import_keys.render,
|
|
858
|
+
wake_key: import_keys.wake,
|
|
859
|
+
fetch_key: import_keys.fetch,
|
|
860
|
+
value: wake_val
|
|
861
|
+
}));
|
|
845
862
|
fetch_val = wake_val;
|
|
846
863
|
}
|
|
847
864
|
if (fetch_val != null && render_mode !== "deferred") throw fail(`${said} sets \`${import_keys.fetch}: '${fetch_val}'\` without \`${import_keys.render}: 'deferred'\` — \`${import_keys.fetch}\` is a hole's timing. Write \`${import_keys.render}: 'deferred', ${import_keys.fetch}: '${fetch_val}'\` for a hole` + (render_mode == null ? `, or \`${import_keys.wake}: '${fetch_val}'\` for an island.` : "."));
|
|
@@ -944,7 +961,11 @@ var FileCompilation = class {
|
|
|
944
961
|
const kids = (node.fragment?.nodes ?? []).filter((n) => !(n.type === "Text" && !String(n.data ?? "").trim()));
|
|
945
962
|
if (kids.length === 0) return;
|
|
946
963
|
if (is_server && kids.length === 1 && kids[0].type === "SnippetBlock" && kids[0].expression?.name === "ogygiaFallback") return;
|
|
947
|
-
throw new
|
|
964
|
+
throw new OgygiaError("region_children_not_portable", {
|
|
965
|
+
host: this.#rel_host,
|
|
966
|
+
tag: local,
|
|
967
|
+
server: is_server
|
|
968
|
+
});
|
|
948
969
|
}
|
|
949
970
|
/** Walk the markup: enforce region-usage rules + surface whether a hydrate island has real
|
|
950
971
|
* children (the app then needs the wire slot revivers). Mutates #has_island_children. */
|
|
@@ -954,7 +975,11 @@ var FileCompilation = class {
|
|
|
954
975
|
const name = node.name || "";
|
|
955
976
|
if (name.includes(".")) {
|
|
956
977
|
const root = name.split(".")[0];
|
|
957
|
-
if (this.#marked_components.has(root) && this.#marked_components.get(root).strategy !== "lake") throw new
|
|
978
|
+
if (this.#marked_components.has(root) && this.#marked_components.get(root).strategy !== "lake") throw new OgygiaError("region_dotted_tag", {
|
|
979
|
+
host: this.#rel_host,
|
|
980
|
+
tag: name,
|
|
981
|
+
import: root
|
|
982
|
+
});
|
|
958
983
|
} else if (this.#marked_components.has(name)) {
|
|
959
984
|
this.#static_placed.add(name);
|
|
960
985
|
const mark = this.#marked_components.get(name);
|
|
@@ -983,13 +1008,22 @@ var FileCompilation = class {
|
|
|
983
1008
|
if (!this.#ctx.pathModule.isAbsolute(p)) return p;
|
|
984
1009
|
return (typeof this.#ctx.pkg_identity === "function" ? this.#ctx.pkg_identity(p) : null) ?? this.#posix_rel(p);
|
|
985
1010
|
}
|
|
986
|
-
/** `
|
|
1011
|
+
/** `host: import { … } — msg` (`region_import_invalid`) — the region-import error formatter. */
|
|
987
1012
|
#err(specifiers, msg) {
|
|
988
|
-
return
|
|
1013
|
+
return new OgygiaError("region_import_invalid", {
|
|
1014
|
+
host: this.#rel_host,
|
|
1015
|
+
names: specifiers,
|
|
1016
|
+
problem: msg
|
|
1017
|
+
});
|
|
989
1018
|
}
|
|
990
|
-
/** `
|
|
1019
|
+
/** `host: import.meta.og.asRegion (local) — msg` (`as_region_invalid`) — the asRegion error
|
|
1020
|
+
* formatter. */
|
|
991
1021
|
#as_err(local, msg) {
|
|
992
|
-
return
|
|
1022
|
+
return new OgygiaError("as_region_invalid", {
|
|
1023
|
+
host: this.#rel_host,
|
|
1024
|
+
name: local,
|
|
1025
|
+
problem: msg
|
|
1026
|
+
});
|
|
993
1027
|
}
|
|
994
1028
|
/** Read asRegion's options object into the same key→value map an import attribute produces, so the
|
|
995
1029
|
* SHARED parser gives asRegion EXACTLY the import-attribute option surface. Object-only and
|
|
@@ -1035,12 +1069,17 @@ var FileCompilation = class {
|
|
|
1035
1069
|
const lang = script_lang_attr(ast.instance) || script_lang_attr(ast.module);
|
|
1036
1070
|
const path = ctx.pathModule;
|
|
1037
1071
|
const rel_host = this.#rel_host = path.relative(ctx.root, id).split(PATH_SEP).join("/");
|
|
1038
|
-
|
|
1039
|
-
throw new
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1072
|
+
const reject_dynamic = (keys) => {
|
|
1073
|
+
throw new OgygiaError("dynamic_region_import", {
|
|
1074
|
+
host: rel_host,
|
|
1075
|
+
keys: keys.join(", "),
|
|
1076
|
+
wake_key: import_keys.wake,
|
|
1077
|
+
render_key: import_keys.render,
|
|
1078
|
+
preset_key: import_keys.preset
|
|
1079
|
+
});
|
|
1080
|
+
};
|
|
1081
|
+
reject_dynamic_region_imports(instance_body, import_keys, reject_dynamic);
|
|
1082
|
+
reject_dynamic_region_imports(module_body, import_keys, reject_dynamic);
|
|
1044
1083
|
/** localName -> { node, cleaned } */
|
|
1045
1084
|
const imports = /* @__PURE__ */ new Map();
|
|
1046
1085
|
/** localName -> { strategy, options } */
|
|
@@ -1140,7 +1179,7 @@ var FileCompilation = class {
|
|
|
1140
1179
|
* Lower — the compilation's fields → rewritten source + `IslandDescriptor[]`. Consumes ONLY the
|
|
1141
1180
|
* analyze pass's fields (it never re-reads the file): creates the MagicString, rewrites each marked
|
|
1142
1181
|
* import to its wrapper / binding / stub, mints the island records, and brands portable snippets.
|
|
1143
|
-
* `err` / `
|
|
1182
|
+
* `err` / `referenced_names` / `marked_import_referenced` are rebuilt here from those fields — pure
|
|
1144
1183
|
* over the AST + host path.
|
|
1145
1184
|
*/
|
|
1146
1185
|
#lower() {
|
|
@@ -1251,7 +1290,11 @@ var FileCompilation = class {
|
|
|
1251
1290
|
}
|
|
1252
1291
|
const entry_spec = info.node.source?.value;
|
|
1253
1292
|
const componentPath = resolve_component_path(entry_spec, origin, ctx);
|
|
1254
|
-
if (!componentPath) throw new
|
|
1293
|
+
if (!componentPath) throw new OgygiaError("region_import_no_specifier", {
|
|
1294
|
+
host: rel_host,
|
|
1295
|
+
name: local,
|
|
1296
|
+
held: false
|
|
1297
|
+
});
|
|
1255
1298
|
const exportName = synthetic_export.get(local);
|
|
1256
1299
|
const comp_rel = this.#component_identity(componentPath);
|
|
1257
1300
|
const id_base = exportName && exportName !== "default" ? `${comp_rel}#${exportName}` : comp_rel;
|
|
@@ -1344,17 +1387,8 @@ var FileCompilation = class {
|
|
|
1344
1387
|
}
|
|
1345
1388
|
const as_region_locals = new Set(as_regions.map((r) => r.compLocal));
|
|
1346
1389
|
if (as_region_locals.size) {
|
|
1347
|
-
const
|
|
1348
|
-
|
|
1349
|
-
if (n.type === "ImportDeclaration" || as_region_nodes.has(n)) continue;
|
|
1350
|
-
if (this.#ast_refs_local(n, local)) return true;
|
|
1351
|
-
}
|
|
1352
|
-
for (const n of module_body) {
|
|
1353
|
-
if (n.type === "ImportDeclaration") continue;
|
|
1354
|
-
if (this.#ast_refs_local(n, local)) return true;
|
|
1355
|
-
}
|
|
1356
|
-
return this.#ast_refs_local(ast.fragment?.nodes ?? [], local);
|
|
1357
|
-
};
|
|
1390
|
+
const outside = this.#referenced_names(as_region_nodes);
|
|
1391
|
+
const referenced_outside = (local) => outside.has(local);
|
|
1358
1392
|
const seen = /* @__PURE__ */ new Set();
|
|
1359
1393
|
for (const compLocal of as_region_locals) {
|
|
1360
1394
|
const info = imports.get(compLocal);
|
|
@@ -1394,7 +1428,16 @@ var FileCompilation = class {
|
|
|
1394
1428
|
}
|
|
1395
1429
|
};
|
|
1396
1430
|
if (portable_allowed) walk_portable(ast.fragment?.nodes ?? []);
|
|
1397
|
-
const
|
|
1431
|
+
const by_start = [...portable_candidates].sort(outer_spans_first);
|
|
1432
|
+
const nested = /* @__PURE__ */ new Set();
|
|
1433
|
+
let reach = -Infinity;
|
|
1434
|
+
for (let i = 0; i < by_start.length; i++) {
|
|
1435
|
+
const c = by_start[i];
|
|
1436
|
+
const twin = by_start[i + 1];
|
|
1437
|
+
if (c.snip.end <= reach || twin && twin.snip.start === c.snip.start && twin.snip.end === c.snip.end) nested.add(c);
|
|
1438
|
+
if (c.snip.end > reach) reach = c.snip.end;
|
|
1439
|
+
}
|
|
1440
|
+
const outer_candidates = portable_candidates.filter((c) => !nested.has(c));
|
|
1398
1441
|
const block_bound = /* @__PURE__ */ new Set();
|
|
1399
1442
|
const bind_pattern = (n) => {
|
|
1400
1443
|
if (!n || typeof n !== "object") return;
|
|
@@ -1476,7 +1519,11 @@ var FileCompilation = class {
|
|
|
1476
1519
|
const store_captures = [];
|
|
1477
1520
|
const store_rewrites = [];
|
|
1478
1521
|
for (const [nm, sites] of stores) {
|
|
1479
|
-
if (nm.startsWith("$$")) throw new
|
|
1522
|
+
if (nm.startsWith("$$")) throw new OgygiaError("snippet_reads_dollar_props", {
|
|
1523
|
+
host: rel_host,
|
|
1524
|
+
snippet: name,
|
|
1525
|
+
name: nm
|
|
1526
|
+
});
|
|
1480
1527
|
const base = nm.slice(1);
|
|
1481
1528
|
const prop = `__og_sub_${base}`;
|
|
1482
1529
|
store_captures.push({
|
|
@@ -1489,8 +1536,18 @@ var FileCompilation = class {
|
|
|
1489
1536
|
prop
|
|
1490
1537
|
});
|
|
1491
1538
|
const trace = sites.map((p) => `${rel_host}:${line_col(source, p.start)}`).join(", ");
|
|
1492
|
-
if (host_declared.has(base) || imports.has(base)) warn_once(`${id}\0${name}\0${nm}\0frozen`,
|
|
1493
|
-
|
|
1539
|
+
if (host_declared.has(base) || imports.has(base)) warn_once(`${id}\0${name}\0${nm}\0frozen`, () => warn("snippet_store_snapshot", {
|
|
1540
|
+
host: rel_host,
|
|
1541
|
+
snippet: name,
|
|
1542
|
+
store: nm,
|
|
1543
|
+
at: trace
|
|
1544
|
+
}));
|
|
1545
|
+
else warn_once(`${id}\0${name}\0${nm}\0unresolved`, () => warn("snippet_store_unverified", {
|
|
1546
|
+
host: rel_host,
|
|
1547
|
+
snippet: name,
|
|
1548
|
+
store: nm,
|
|
1549
|
+
at: trace
|
|
1550
|
+
}));
|
|
1494
1551
|
}
|
|
1495
1552
|
const cleaned_imports = [];
|
|
1496
1553
|
const seen_imports = /* @__PURE__ */ new Set();
|
|
@@ -1506,7 +1563,11 @@ var FileCompilation = class {
|
|
|
1506
1563
|
cleaned_imports.push(text);
|
|
1507
1564
|
}
|
|
1508
1565
|
} else if (host_declared.has(nm)) {
|
|
1509
|
-
if (store_like.has(nm)) warn_once(`${id}\0${name}\0${nm}\0object`,
|
|
1566
|
+
if (store_like.has(nm)) warn_once(`${id}\0${name}\0${nm}\0object`, () => warn("snippet_captures_store", {
|
|
1567
|
+
host: rel_host,
|
|
1568
|
+
snippet: name,
|
|
1569
|
+
store: nm
|
|
1570
|
+
}));
|
|
1510
1571
|
captures.push(nm);
|
|
1511
1572
|
} else if (module_imports.has(nm)) {
|
|
1512
1573
|
const text = module_imports.get(nm).trim();
|
|
@@ -1604,6 +1665,10 @@ var FileCompilation = class {
|
|
|
1604
1665
|
* @param raw the text between the `with {` and `}`
|
|
1605
1666
|
* @returns
|
|
1606
1667
|
*/
|
|
1668
|
+
/** Span order for the portable-snippet nesting sweep: by start, the longer span first on a tie. */
|
|
1669
|
+
function outer_spans_first(a, b) {
|
|
1670
|
+
return a.snip.start - b.snip.start || b.snip.end - a.snip.end;
|
|
1671
|
+
}
|
|
1607
1672
|
function parse_import_attrs(raw) {
|
|
1608
1673
|
const attrs = /* @__PURE__ */ new Map();
|
|
1609
1674
|
IMPORT_ATTR_PAIR_G.lastIndex = 0;
|
|
@@ -1640,7 +1705,10 @@ function ts_literal_ranges(source, id) {
|
|
|
1640
1705
|
const ranges = [];
|
|
1641
1706
|
const walk = (n) => {
|
|
1642
1707
|
if (!n || typeof n !== "object") return;
|
|
1643
|
-
if (Array.isArray(n))
|
|
1708
|
+
if (Array.isArray(n)) {
|
|
1709
|
+
n.forEach(walk);
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1644
1712
|
const node = n;
|
|
1645
1713
|
const t = node.type;
|
|
1646
1714
|
const is_str = (t === "Literal" || t === "StringLiteral") && typeof node.value === "string";
|
|
@@ -1699,9 +1767,13 @@ var TsRegionCompilation = class {
|
|
|
1699
1767
|
#posix_rel(abs) {
|
|
1700
1768
|
return this.#path.relative(this.#root, abs).split(PATH_SEP).join("/");
|
|
1701
1769
|
}
|
|
1702
|
-
/** `
|
|
1770
|
+
/** `host: import.meta.og.asRegion (local) — msg` (`as_region_invalid`). */
|
|
1703
1771
|
#as_err(local, msg) {
|
|
1704
|
-
return
|
|
1772
|
+
return new OgygiaError("as_region_invalid", {
|
|
1773
|
+
host: this.#rel_host,
|
|
1774
|
+
name: local,
|
|
1775
|
+
problem: msg
|
|
1776
|
+
});
|
|
1705
1777
|
}
|
|
1706
1778
|
/**
|
|
1707
1779
|
* Same policy as transformHost's resolve_component_path: $lib/relative → absolute file path,
|
|
@@ -1732,18 +1804,49 @@ var TsRegionCompilation = class {
|
|
|
1732
1804
|
const id_base = exportName && exportName !== "default" ? `${comp_rel}#${exportName}` : comp_rel;
|
|
1733
1805
|
const fetchKey = this.#import_keys.fetch;
|
|
1734
1806
|
const renderKey = this.#import_keys.render;
|
|
1735
|
-
if (marker.fetch != null && marker.render == null) throw new
|
|
1807
|
+
if (marker.fetch != null && marker.render == null) throw new OgygiaError("held_fetch_without_render", {
|
|
1808
|
+
host: this.#rel_host,
|
|
1809
|
+
fetch_key: fetchKey,
|
|
1810
|
+
render_key: renderKey,
|
|
1811
|
+
wake_key: this.#wakeKey,
|
|
1812
|
+
value: marker.fetch
|
|
1813
|
+
});
|
|
1736
1814
|
if (marker.render != null) {
|
|
1737
|
-
if (marker.render !== "deferred") throw
|
|
1815
|
+
if (marker.render !== "deferred") throw marker.render === "live" ? new OgygiaError("held_render_live", {
|
|
1816
|
+
host: this.#rel_host,
|
|
1817
|
+
render_key: renderKey
|
|
1818
|
+
}) : new OgygiaError("held_render_unknown", {
|
|
1819
|
+
host: this.#rel_host,
|
|
1820
|
+
render_key: renderKey,
|
|
1821
|
+
value: marker.render
|
|
1822
|
+
});
|
|
1738
1823
|
if (marker.wake != null) {
|
|
1739
|
-
if (marker.fetch != null) throw new
|
|
1740
|
-
|
|
1824
|
+
if (marker.fetch != null) throw new OgygiaError("held_hole_timed_twice", {
|
|
1825
|
+
host: this.#rel_host,
|
|
1826
|
+
render_key: renderKey,
|
|
1827
|
+
fetch_key: fetchKey,
|
|
1828
|
+
wake_key: this.#wakeKey,
|
|
1829
|
+
fetch: marker.fetch,
|
|
1830
|
+
wake: marker.wake
|
|
1831
|
+
});
|
|
1832
|
+
const wake = marker.wake;
|
|
1833
|
+
warn_once(`deferred-wake:${this.#rel_host}:ts:${wake}`, () => warn("hole_wake_deprecated", {
|
|
1834
|
+
host: this.#rel_host,
|
|
1835
|
+
render_key: renderKey,
|
|
1836
|
+
wake_key: this.#wakeKey,
|
|
1837
|
+
fetch_key: fetchKey,
|
|
1838
|
+
value: wake
|
|
1839
|
+
}));
|
|
1741
1840
|
}
|
|
1742
1841
|
const dval = marker.fetch ?? marker.wake ?? "load";
|
|
1743
1842
|
let when;
|
|
1744
1843
|
if (DEFER_STRATEGIES.has(dval)) when = dval;
|
|
1745
1844
|
else if (is_media_query(dval)) when = dval;
|
|
1746
|
-
else throw new
|
|
1845
|
+
else throw new OgygiaError("held_fetch_not_timing", {
|
|
1846
|
+
host: this.#rel_host,
|
|
1847
|
+
fetch_key: fetchKey,
|
|
1848
|
+
value: dval
|
|
1849
|
+
});
|
|
1747
1850
|
const options = { when };
|
|
1748
1851
|
if (when === "visible" && this.#ctx.visibleMargin != null) options.margin = this.#ctx.visibleMargin;
|
|
1749
1852
|
const identity = regionIdentity(id_base, {
|
|
@@ -1853,9 +1956,20 @@ var TsRegionCompilation = class {
|
|
|
1853
1956
|
const has_fetch = attrs.has(fetchKey);
|
|
1854
1957
|
if (!has_render && !has_region && !has_wake && !has_fetch) continue;
|
|
1855
1958
|
if (inside_literal(m.index)) continue;
|
|
1856
|
-
if (has_region && attrs.size > 1 || has_render && [...attrs.keys()].some((k) => k !== renderKey && k !== wakeKey && k !== fetchKey) || !has_render && has_wake && attrs.size > 1) throw new
|
|
1959
|
+
if (has_region && attrs.size > 1 || has_render && [...attrs.keys()].some((k) => k !== renderKey && k !== wakeKey && k !== fetchKey) || !has_render && has_wake && attrs.size > 1) throw new OgygiaError("held_marker_mixed", {
|
|
1960
|
+
host: rel_host,
|
|
1961
|
+
name: local,
|
|
1962
|
+
region_key: regionKey,
|
|
1963
|
+
wake_key: wakeKey,
|
|
1964
|
+
render_key: renderKey,
|
|
1965
|
+
fetch_key: fetchKey
|
|
1966
|
+
});
|
|
1857
1967
|
const componentPath = this.#resolve_spec(spec);
|
|
1858
|
-
if (!componentPath) throw new
|
|
1968
|
+
if (!componentPath) throw new OgygiaError("region_import_no_specifier", {
|
|
1969
|
+
host: rel_host,
|
|
1970
|
+
name: local,
|
|
1971
|
+
held: true
|
|
1972
|
+
});
|
|
1859
1973
|
const marker = has_render ? {
|
|
1860
1974
|
render: attrs.get(renderKey),
|
|
1861
1975
|
wake: attrs.get(wakeKey),
|
package/dist/context-bridge.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { batch } from "./ref-watch.js";
|
|
2
1
|
import { REF_WIRE_KEY, ref_reducer, ref_reviver } from "./ref.js";
|
|
2
|
+
import { batch } from "./ref-watch.js";
|
|
3
3
|
import { register_wire_kind } from "./live-transport.js";
|
|
4
4
|
import { register_derived_kind, register_store_kind } from "./store-transport.js";
|
|
5
5
|
import { register_snippet_kind } from "./region-snippet.js";
|
|
6
6
|
import { is_branded_fn, register_fn_kind } from "./fn-transport.js";
|
|
7
|
-
import { boundary_problems
|
|
7
|
+
import { boundary_problems } from "./boundary.js";
|
|
8
8
|
import { PAGE_CTX_MARKER, record_ctx } from "./context-registry.js";
|
|
9
9
|
import { escape_script_text } from "./escape.js";
|
|
10
|
+
import { warn } from "./messages/island.js";
|
|
10
11
|
import { getContext, setContext as setContext$1 } from "svelte";
|
|
11
12
|
import { DEV } from "esm-env";
|
|
12
13
|
import { parse, stringify } from "devalue";
|
|
@@ -102,16 +103,23 @@ function warn_ctx_size(map, total) {
|
|
|
102
103
|
} catch {}
|
|
103
104
|
sizes.sort((a, b) => b[1] - a[1]);
|
|
104
105
|
const top = sizes.slice(0, 3).map(([k, n]) => `'${k}' ~${(n / 1024).toFixed(1)}kB`).join(", ");
|
|
105
|
-
|
|
106
|
+
warn("context_marker_large", {
|
|
107
|
+
size: (total / 1024).toFixed(1),
|
|
108
|
+
top
|
|
109
|
+
});
|
|
106
110
|
}
|
|
107
111
|
/** DEV: explain a dropped (or degraded-but-bridged) context key via the classifier. */
|
|
108
112
|
function warn_boundary(key, value, dropped) {
|
|
109
113
|
const problems = boundary_problems(value, key);
|
|
110
114
|
if (dropped && problems.length === 0) {
|
|
111
|
-
|
|
115
|
+
warn("context_dropped", { key });
|
|
112
116
|
return;
|
|
113
117
|
}
|
|
114
|
-
for (const f of problems) if (dropped || f.kind === "warn")
|
|
118
|
+
for (const f of problems) if (dropped || f.kind === "warn") warn("context_unserializable", {
|
|
119
|
+
key,
|
|
120
|
+
path: f.path || void 0,
|
|
121
|
+
detail: f.detail
|
|
122
|
+
});
|
|
115
123
|
}
|
|
116
124
|
/** Decode one serialized provider payload; a corrupt payload yields nothing (never breaks hydration). */
|
|
117
125
|
function parse_ctx(text) {
|
package/dist/context.d.ts
CHANGED
|
@@ -60,4 +60,13 @@ export declare function claim_region_css(hrefs: string[]): string[];
|
|
|
60
60
|
* Client / no-request → false (SSR already emitted).
|
|
61
61
|
*/
|
|
62
62
|
export declare function claimRuntimeEmit(): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Note a top-level `defer: 'load'` hole's endpoint for this request: the head starts its request
|
|
65
|
+
* during the parse (early-holes.ts), written once by the handle or `document()`, which take the
|
|
66
|
+
* list. Identical holes share one endpoint, and one request. Client / no-request: nothing to note.
|
|
67
|
+
*/
|
|
68
|
+
export declare function note_early_hole(endpoint: string): void;
|
|
69
|
+
/** This request's noted `load` hole endpoints, taken once (the head that writes them). `request`: the
|
|
70
|
+
* one the caller holds (the handle's event); else the current render's. */
|
|
71
|
+
export declare function take_early_holes(request?: Request): string[];
|
|
63
72
|
export { isNested, setNested };
|
package/dist/context.js
CHANGED
|
@@ -140,4 +140,33 @@ function claimRuntimeEmit() {
|
|
|
140
140
|
return false;
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
|
-
|
|
143
|
+
/** Each request's noted `load` hole endpoints, by its `Request`: the render's event and the handle's
|
|
144
|
+
* are not one object, the request they carry is. */
|
|
145
|
+
const early_holes = /* @__PURE__ */ new WeakMap();
|
|
146
|
+
/**
|
|
147
|
+
* Note a top-level `defer: 'load'` hole's endpoint for this request: the head starts its request
|
|
148
|
+
* during the parse (early-holes.ts), written once by the handle or `document()`, which take the
|
|
149
|
+
* list. Identical holes share one endpoint, and one request. Client / no-request: nothing to note.
|
|
150
|
+
*/
|
|
151
|
+
function note_early_hole(endpoint) {
|
|
152
|
+
try {
|
|
153
|
+
const { request } = getRequestEvent();
|
|
154
|
+
let seen = early_holes.get(request);
|
|
155
|
+
if (!seen) early_holes.set(request, seen = /* @__PURE__ */ new Set());
|
|
156
|
+
seen.add(endpoint);
|
|
157
|
+
} catch {}
|
|
158
|
+
}
|
|
159
|
+
/** This request's noted `load` hole endpoints, taken once (the head that writes them). `request`: the
|
|
160
|
+
* one the caller holds (the handle's event); else the current render's. */
|
|
161
|
+
function take_early_holes(request) {
|
|
162
|
+
if (!request) try {
|
|
163
|
+
request = getRequestEvent().request;
|
|
164
|
+
} catch {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
const seen = early_holes.get(request);
|
|
168
|
+
if (!seen) return [];
|
|
169
|
+
early_holes.delete(request);
|
|
170
|
+
return [...seen];
|
|
171
|
+
}
|
|
172
|
+
export { claimRuntimeEmit, claim_kit_island, claim_region_css, documentIsCsrTrue, error_route_is_csr_true, isHoleInline, isInLake, isInLiveSnippet, isNested, isOgygiaPage, note_early_hole, route_is_csr_true, setHoleInline, setInLake, setInLiveSnippet, setNested, take_early_holes };
|
package/dist/document.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface DocumentOptions {
|
|
|
13
13
|
lang?: string;
|
|
14
14
|
/** Seed for `$app/state` inside islands (`page.data`/`params`/`url`, `route.id`, `form`). The router
|
|
15
15
|
* passes it so islands on a rendered page read `$page` just like on a Kit-served page. Promises in
|
|
16
|
-
* `data`/`form` aren't streamed here — a non-serializable leaf
|
|
16
|
+
* `data`/`form` aren't streamed here — a non-serializable leaf is left out where it sits. */
|
|
17
17
|
pageState?: {
|
|
18
18
|
url?: {
|
|
19
19
|
href?: string;
|
package/dist/document.js
CHANGED
|
@@ -8,6 +8,9 @@ import { kit_render_context } from "./server/kit-context.js";
|
|
|
8
8
|
import { open_ask_scope, read_seed_ask, record_page } from "./page-seed-registry.js";
|
|
9
9
|
import { shape_page_data } from "./server/seed-shape.js";
|
|
10
10
|
import { escape_text } from "./escape.js";
|
|
11
|
+
import { take_early_holes } from "./context.js";
|
|
12
|
+
import { early_holes_head } from "./early-holes-head.js";
|
|
13
|
+
import { add_early_holes_csp, with_early_holes_meta_csp } from "./server/early-holes-csp.js";
|
|
11
14
|
import { page_declares_dev_hmr_script, page_declares_router_meta, page_declares_runtime_script, runtime_first } from "./server/head-presence.js";
|
|
12
15
|
import { render } from "svelte/server";
|
|
13
16
|
import { stringify } from "devalue";
|
|
@@ -95,6 +98,8 @@ async function document(of, options = {}) {
|
|
|
95
98
|
if (enabled && !page_declares_router_meta(head_so_far())) head.push(`<meta name="ogygia-router" content="${viewTransitions ? "vt" : "plain"}">`);
|
|
96
99
|
if (runtime_url && !page_declares_runtime_script(head_so_far())) head.push(runtime_bootstrap());
|
|
97
100
|
if (dev_hmr_url && !page_declares_dev_hmr_script(head_so_far())) head.push(`<script type="module" data-ogygia-dev-hmr src="${dev_hmr_url}"><\/script>`);
|
|
101
|
+
const early = take_early_holes();
|
|
102
|
+
head.push(early_holes_head(early));
|
|
98
103
|
const ask = options.pageState ? read_seed_ask() : void 0;
|
|
99
104
|
if (options.pageState && (!ask || ask.wanted)) {
|
|
100
105
|
const s = options.pageState;
|
|
@@ -113,10 +118,11 @@ async function document(of, options = {}) {
|
|
|
113
118
|
head.push(`<script type="application/ogygia-page" data-ogygia-page${format}>${payload.text}<\/script>`);
|
|
114
119
|
}
|
|
115
120
|
}
|
|
116
|
-
const html = `<!doctype html>\n<html lang="${escape_text(options.lang ?? "en")}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">` + runtime_first(head.join(""), null) + `</head><body>${r.body}</body></html>`;
|
|
121
|
+
const html = `<!doctype html>\n<html lang="${escape_text(options.lang ?? "en")}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">` + (early.length ? with_early_holes_meta_csp(runtime_first(head.join(""), null)) : runtime_first(head.join(""), null)) + `</head><body>${r.body}</body></html>`;
|
|
117
122
|
const headers = new Headers({ "content-type": "text/html; charset=utf-8" });
|
|
118
123
|
if (!current_facts()?.storable) headers.set("cache-control", "no-store");
|
|
119
124
|
if (options.headers) for (const [k, v] of new Headers(options.headers)) headers.set(k, v);
|
|
125
|
+
if (early.length) add_early_holes_csp(headers);
|
|
120
126
|
return new Response(html, {
|
|
121
127
|
status: options.status ?? 200,
|
|
122
128
|
headers
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The early start's script tag, the same bytes on every page (its CSP hash is computed from it). */
|
|
2
|
+
export declare const EARLY_HOLES_TAG: string;
|
|
3
|
+
/** The head's early start for `endpoints` (the request's `load` holes, each once): the data block,
|
|
4
|
+
* then the script that reads it. Nothing for none. */
|
|
5
|
+
export declare function early_holes_head(endpoints: readonly string[]): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EARLY_HOLES_ID, EARLY_HOLES_KEY, start_early_holes } from "./early-holes.js";
|
|
2
|
+
import { script } from "./script.js";
|
|
3
|
+
// src/early-holes-head.ts
|
|
4
|
+
/**
|
|
5
|
+
* The head's early start (./early-holes.ts), as tags: written by the handle and `document()`, and
|
|
6
|
+
* read by the tests that run it. Kept apart from ./early-holes.ts so the runtime, which only reads
|
|
7
|
+
* the global, never loads `script()`.
|
|
8
|
+
*/
|
|
9
|
+
/** The early start's script tag, the same bytes on every page (its CSP hash is computed from it). */
|
|
10
|
+
const EARLY_HOLES_TAG = script(start_early_holes, EARLY_HOLES_ID, EARLY_HOLES_KEY);
|
|
11
|
+
/** The head's early start for `endpoints` (the request's `load` holes, each once): the data block,
|
|
12
|
+
* then the script that reads it. Nothing for none. */
|
|
13
|
+
function early_holes_head(endpoints) {
|
|
14
|
+
if (endpoints.length === 0) return "";
|
|
15
|
+
return script({
|
|
16
|
+
json: [...endpoints],
|
|
17
|
+
id: EARLY_HOLES_ID
|
|
18
|
+
}) + EARLY_HOLES_TAG;
|
|
19
|
+
}
|
|
20
|
+
export { EARLY_HOLES_TAG, early_holes_head };
|