@ogygia/core 0.12.2 → 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 +83 -74
- 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.d.ts +6 -5
- 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
package/dist/plugin/css.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { router_css_active, router_css_of } from "../router-css.js";
|
|
2
2
|
import { claim_region_css } from "../context.js";
|
|
3
|
+
import { warn } from "../messages/server.js";
|
|
3
4
|
import { DEV } from "esm-env";
|
|
5
|
+
import { flights } from "@ogygia/machine";
|
|
4
6
|
// src/plugin/css.ts
|
|
5
7
|
/**
|
|
6
8
|
* `ogygia/plugin/css` — the CSS of components a programmatic router renders (see the server-router-css
|
|
@@ -14,24 +16,23 @@ import { DEV } from "esm-env";
|
|
|
14
16
|
* plugin's server realm) — and it is imported on the first call, never at module load.
|
|
15
17
|
*/
|
|
16
18
|
const STYLE_CLOSE_G = /<\/style/gi;
|
|
17
|
-
|
|
19
|
+
const registry = flights({
|
|
20
|
+
name: "router-css registry",
|
|
21
|
+
run: () => import("virtual:ogygia/router-css")
|
|
22
|
+
});
|
|
18
23
|
let warned_inactive = false;
|
|
19
|
-
function registry_ready() {
|
|
20
|
-
if (rcss_ready === void 0) try {
|
|
21
|
-
rcss_ready = import("virtual:ogygia/router-css").catch(() => null);
|
|
22
|
-
} catch {
|
|
23
|
-
rcss_ready = null;
|
|
24
|
-
}
|
|
25
|
-
return rcss_ready;
|
|
26
|
-
}
|
|
27
24
|
/** Head tags for the components ONE render places (a layout chain + its page or error component):
|
|
28
25
|
* each component's whole-tree CSS, linked once per request. */
|
|
29
26
|
async function componentCssHead(components) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
let read = true;
|
|
28
|
+
try {
|
|
29
|
+
await registry.get();
|
|
30
|
+
} catch {
|
|
31
|
+
read = false;
|
|
32
|
+
}
|
|
33
|
+
if (DEV && read && !warned_inactive && components.length && !router_css_active()) {
|
|
33
34
|
warned_inactive = true;
|
|
34
|
-
|
|
35
|
+
warn("router_css_inactive");
|
|
35
36
|
}
|
|
36
37
|
const entries = components.flatMap((c) => router_css_of(c));
|
|
37
38
|
if (!entries.length) return "";
|
package/dist/plugin/facts.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export interface RequestFacts {
|
|
|
36
36
|
export declare function facts_of(request: Request): RequestFacts;
|
|
37
37
|
/** Core only (hooks.ts): how the running code's Request is found. */
|
|
38
38
|
export declare function set_current_request(fn: (() => Request | undefined) | null): void;
|
|
39
|
+
/** The Request the running code belongs to, or undefined outside one (the client, a test). */
|
|
40
|
+
export declare function current_request(): Request | undefined;
|
|
39
41
|
/** The facts of the request the running code belongs to, or null outside one (the client, a test). */
|
|
40
42
|
export declare function current_facts(): RequestFacts | null;
|
|
41
43
|
/** Name the first reason a render is per-visitor (later reasons do not replace it). */
|
package/dist/plugin/facts.js
CHANGED
|
@@ -21,17 +21,21 @@ function facts_of(request) {
|
|
|
21
21
|
function set_current_request(fn) {
|
|
22
22
|
slot.current = fn;
|
|
23
23
|
}
|
|
24
|
-
/** The
|
|
25
|
-
function
|
|
24
|
+
/** The Request the running code belongs to, or undefined outside one (the client, a test). */
|
|
25
|
+
function current_request() {
|
|
26
26
|
try {
|
|
27
|
-
|
|
28
|
-
return request ? facts_of(request) : null;
|
|
27
|
+
return slot.current?.();
|
|
29
28
|
} catch {
|
|
30
|
-
return
|
|
29
|
+
return;
|
|
31
30
|
}
|
|
32
31
|
}
|
|
32
|
+
/** The facts of the request the running code belongs to, or null outside one (the client, a test). */
|
|
33
|
+
function current_facts() {
|
|
34
|
+
const request = current_request();
|
|
35
|
+
return request ? facts_of(request) : null;
|
|
36
|
+
}
|
|
33
37
|
/** Name the first reason a render is per-visitor (later reasons do not replace it). */
|
|
34
38
|
function mark_per_visitor(facts, reason) {
|
|
35
39
|
if (facts.perVisitor === null) facts.perVisitor = reason;
|
|
36
40
|
}
|
|
37
|
-
export { current_facts, facts_of, mark_per_visitor, set_current_request };
|
|
41
|
+
export { current_facts, current_request, facts_of, mark_per_visitor, set_current_request };
|
package/dist/plugin/hooks.d.ts
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SHARED HOOKS — how plugins (and core) talk to each other: the same way core talks to them. A
|
|
3
|
-
* plugin implements a hook as a method of its server half; anyone calls it through `app`:
|
|
4
|
-
*
|
|
5
|
-
* app.notify.invalidate(tags) every implementation runs (resolves when all are done)
|
|
6
|
-
* app.ask.lastBuild(version) the first answer that is not `undefined`, in plugin order
|
|
7
|
-
*
|
|
8
|
-
* Nobody implementing a hook is normal: `notify` does nothing, `ask` answers `undefined`. Core owns
|
|
9
|
-
* the common names below; a plugin's own hooks carry its name (`federationThaw`), added by
|
|
10
|
-
* declaration merging:
|
|
11
|
-
*
|
|
12
|
-
* declare module 'ogygia/plugin' { interface ServerHooks { myThing(x: number): void } }
|
|
13
|
-
*
|
|
14
|
-
* One global slot: every module instance dispatches over the same implementations.
|
|
15
|
-
*/
|
|
16
1
|
/** The shared hooks. Each is optional on a plugin; the signature is the contract. */
|
|
17
2
|
export interface ServerHooks {
|
|
18
3
|
/** Drop every stored page carrying any of `tags` (a peer said they are stale). Never re-announced. */
|
|
@@ -27,7 +12,12 @@ export interface ServerHooks {
|
|
|
27
12
|
export declare function register_hooks(impl: object): () => void;
|
|
28
13
|
export type Notify = { [K in keyof ServerHooks]: (...args: Parameters<ServerHooks[K]>) => Promise<void>; };
|
|
29
14
|
export type Ask = { [K in keyof ServerHooks]: (...args: Parameters<ServerHooks[K]>) => Promise<Awaited<ReturnType<ServerHooks[K]>> | undefined>; };
|
|
30
|
-
/** Every implementation of the named hook runs; a failing one is logged
|
|
15
|
+
/** Every implementation of the named hook runs; a failing one is logged and does not stop the
|
|
16
|
+
* others. Once all ran, the notify rejects with what failed (the one error, or an
|
|
17
|
+
* AggregateError): "done" and "done, but one could not" are different answers, like the ask's
|
|
18
|
+
* (a peer said done for a thaw its store failed to apply, #287). */
|
|
31
19
|
export declare const notify: Notify;
|
|
32
|
-
/** The first implementation that answers something other than `undefined`.
|
|
20
|
+
/** The first implementation that answers something other than `undefined`. When none answered and
|
|
21
|
+
* one threw, the ask throws that error: "nobody knows" and "the one who knows could not say" are
|
|
22
|
+
* different answers (a store down once read as "no store", and the deploy thaw was lost, #198). */
|
|
33
23
|
export declare const ask: Ask;
|
package/dist/plugin/hooks.js
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
|
+
import { warn } from "../messages/server.js";
|
|
1
2
|
// src/plugin/hooks.ts
|
|
3
|
+
/**
|
|
4
|
+
* SHARED HOOKS — how plugins (and core) talk to each other: the same way core talks to them. A
|
|
5
|
+
* plugin implements a hook as a method of its server half; anyone calls it through `app`:
|
|
6
|
+
*
|
|
7
|
+
* app.notify.invalidate(tags) every implementation runs (resolves when all are done;
|
|
8
|
+
* rejects then if one failed)
|
|
9
|
+
* app.ask.lastBuild(version) the first answer that is not `undefined`, in plugin order
|
|
10
|
+
*
|
|
11
|
+
* Nobody implementing a hook is normal: `notify` does nothing, `ask` answers `undefined`. Core owns
|
|
12
|
+
* the common names below; a plugin's own hooks carry its name (`federationThaw`), added by
|
|
13
|
+
* declaration merging:
|
|
14
|
+
*
|
|
15
|
+
* declare module 'ogygia/plugin' { interface ServerHooks { myThing(x: number): void } }
|
|
16
|
+
*
|
|
17
|
+
* One global slot: every module instance dispatches over the same implementations.
|
|
18
|
+
*/
|
|
2
19
|
const implementations = globalThis[Symbol.for("ogygia.server-hooks.v1")] ??= [];
|
|
3
20
|
/** Core only: a set of hook implementations joins (a plugin's server half, or core's own). Keyed by
|
|
4
21
|
* identity; returns the leave. */
|
|
@@ -10,20 +27,29 @@ function register_hooks(impl) {
|
|
|
10
27
|
if (at !== -1) implementations.splice(at, 1);
|
|
11
28
|
};
|
|
12
29
|
}
|
|
13
|
-
/** Every implementation of the named hook runs; a failing one is logged
|
|
30
|
+
/** Every implementation of the named hook runs; a failing one is logged and does not stop the
|
|
31
|
+
* others. Once all ran, the notify rejects with what failed (the one error, or an
|
|
32
|
+
* AggregateError): "done" and "done, but one could not" are different answers, like the ask's
|
|
33
|
+
* (a peer said done for a thaw its store failed to apply, #287). */
|
|
14
34
|
const notify = new Proxy({}, { get: (_, name) => async (...args) => {
|
|
35
|
+
let failed = null;
|
|
15
36
|
for (const impl of implementations.slice()) {
|
|
16
37
|
const fn = impl[name];
|
|
17
38
|
if (typeof fn !== "function") continue;
|
|
18
39
|
try {
|
|
19
40
|
await fn.apply(impl, args);
|
|
20
41
|
} catch (e) {
|
|
21
|
-
|
|
42
|
+
warn("plugin_hook_failed", { name }, e);
|
|
43
|
+
(failed ??= []).push(e);
|
|
22
44
|
}
|
|
23
45
|
}
|
|
46
|
+
if (failed) throw failed.length === 1 ? failed[0] : new AggregateError(failed, `${failed.length} implementations of ${name} failed`);
|
|
24
47
|
} });
|
|
25
|
-
/** The first implementation that answers something other than `undefined`.
|
|
48
|
+
/** The first implementation that answers something other than `undefined`. When none answered and
|
|
49
|
+
* one threw, the ask throws that error: "nobody knows" and "the one who knows could not say" are
|
|
50
|
+
* different answers (a store down once read as "no store", and the deploy thaw was lost, #198). */
|
|
26
51
|
const ask = new Proxy({}, { get: (_, name) => async (...args) => {
|
|
52
|
+
let failed = null;
|
|
27
53
|
for (const impl of implementations.slice()) {
|
|
28
54
|
const fn = impl[name];
|
|
29
55
|
if (typeof fn !== "function") continue;
|
|
@@ -31,8 +57,10 @@ const ask = new Proxy({}, { get: (_, name) => async (...args) => {
|
|
|
31
57
|
const answer = await fn.apply(impl, args);
|
|
32
58
|
if (answer !== void 0) return answer;
|
|
33
59
|
} catch (e) {
|
|
34
|
-
|
|
60
|
+
warn("plugin_hook_failed", { name }, e);
|
|
61
|
+
failed ??= { error: e };
|
|
35
62
|
}
|
|
36
63
|
}
|
|
64
|
+
if (failed) throw failed.error;
|
|
37
65
|
} });
|
|
38
66
|
export { ask, notify, register_hooks };
|
package/dist/plugin/index.d.ts
CHANGED
|
@@ -30,6 +30,10 @@ export interface ServerApp<Options = undefined> {
|
|
|
30
30
|
/** Record a server-realm event into the current request's devtools stream (a no-op unless
|
|
31
31
|
* devtools is on for that browser). */
|
|
32
32
|
devtools(event: DevtoolsEventInput): void;
|
|
33
|
+
/** Keeps `work` alive past the response of the request the running code belongs to: it is handed
|
|
34
|
+
* to the platform's `waitUntil` when there is one. Outside a request, or on a platform without
|
|
35
|
+
* one, it runs on in the process. Never throws. An outbox's `waitUntil`. */
|
|
36
|
+
keepAlive(work: Promise<unknown>): void;
|
|
33
37
|
/** Warn once per message, prefixed with the plugin's name. */
|
|
34
38
|
warn(message: string): void;
|
|
35
39
|
}
|
|
@@ -112,8 +116,11 @@ export type ServerPlugin<Options = undefined, State = undefined> = Partial<Serve
|
|
|
112
116
|
/** SEQUENTIAL — the page's response, before it streams out. A Response replaces it. */
|
|
113
117
|
response?(ctx: RequestContext<Options, State>, response: Response): MaybePromise<void | Response>;
|
|
114
118
|
/** PARALLEL — the request's end, always (an answered, failed or streamed request included). Must
|
|
115
|
-
* not throw
|
|
116
|
-
|
|
119
|
+
* not throw. Work it leaves running that must finish (a send) it returns: the platform's
|
|
120
|
+
* `waitUntil` keeps it alive past the response when there is one, and otherwise it runs on by
|
|
121
|
+
* itself (a long-running server keeps it alive). The response never waits for it. A failure in
|
|
122
|
+
* it never fails the request: say what went wrong yourself. */
|
|
123
|
+
done?(ctx: RequestContext<Options, State>): void | Promise<void>;
|
|
117
124
|
};
|
|
118
125
|
/** Typed identity: a plugin's server half. */
|
|
119
126
|
export declare function defineServer<Options = undefined, State = undefined>(plugin: ServerPlugin<Options, State>): ServerPlugin<Options, State>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Scope } from "@ogygia/machine";
|
|
2
|
+
/** The owner of `request` (made on first touch). */
|
|
3
|
+
export declare function request_scope(request: Request): Scope;
|
|
4
|
+
/** The owner of the request the running code belongs to, or null outside one. */
|
|
5
|
+
export declare function current_request_scope(): Scope | null;
|
|
6
|
+
/** A value per request: `make` runs the first time a request asks, and what it made is disposed
|
|
7
|
+
* when that request ends. Asked after the end, it is made and disposed at once. */
|
|
8
|
+
export declare function request_local<T extends Disposable>(make: (owner: Scope) => T): (request: Request) => T;
|
|
9
|
+
/** Says that a cleanup of a request's work failed (`request_cleanup_failed`, the error after it):
|
|
10
|
+
* for an ending nobody waits on, such as a stream source ended as the visitor leaves. */
|
|
11
|
+
export declare function cleanup_failed(error: unknown): void;
|
|
12
|
+
/** Ends a request's owner. A cleanup that throws is said, never thrown: the response is not its. */
|
|
13
|
+
export declare function end_request_scope(owner: Scope): void;
|
|
14
|
+
/**
|
|
15
|
+
* Core only (the handle): `response` to `request`, whose end ends `owner`. No body, or one the
|
|
16
|
+
* platform will not read (`body_unread`): it ends now. A body: the response carries it through as
|
|
17
|
+
* it is, chunk by chunk, and its last chunk read or its cancel ends the owner; the owner ending
|
|
18
|
+
* first (the visitor left) cancels the body and ends the response.
|
|
19
|
+
*/
|
|
20
|
+
export declare function own_response(owner: Scope, response: Response, request: Request): Response;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { current_request } from "./facts.js";
|
|
2
|
+
import { warn } from "../messages/server.js";
|
|
3
|
+
import { note_response_end } from "../server/rules.js";
|
|
4
|
+
import { scope } from "@ogygia/machine";
|
|
5
|
+
// src/plugin/request-scope.ts
|
|
6
|
+
/**
|
|
7
|
+
* THE REQUEST'S OWNER — one scope per server request: the timers, streams, readers and fetches the
|
|
8
|
+
* request starts are its, and go when it ends.
|
|
9
|
+
*
|
|
10
|
+
* const owner = request_scope(event.request);
|
|
11
|
+
* owner.timeout(give_up, 5000); // cleared when the request ends
|
|
12
|
+
* owner.defer(() => void reader.cancel()); // the reader stops with it
|
|
13
|
+
* fetch(url, { signal: owner.signal }); // aborted when the visitor leaves
|
|
14
|
+
*
|
|
15
|
+
* It ends at the first of:
|
|
16
|
+
* - the response ends: its body is read to the end, or cancelled (a streamed page included: its
|
|
17
|
+
* body is the response's, so it ends when the stream does), or it has a body the platform will
|
|
18
|
+
* not read (a HEAD answer, or a page SvelteKit turns into a 304), which ends at once;
|
|
19
|
+
* - the visitor leaves: `request.signal` aborts.
|
|
20
|
+
*
|
|
21
|
+
* The handle makes it when the request comes in and closes it at the end of the response
|
|
22
|
+
* (`own_response`). Code with no handle around it (a test, a render off-request) still gets one,
|
|
23
|
+
* made on first touch and closed when `request.signal` aborts.
|
|
24
|
+
*
|
|
25
|
+
* A value that lives as long as one request is a `request_local`: made the first time the request
|
|
26
|
+
* asks for it, and let go (disposed) when the request ends. Keyed by the request, like its facts.
|
|
27
|
+
*
|
|
28
|
+
* One global slot, not module scope: a plugin package and core can end up as two module instances
|
|
29
|
+
* of this file (src beside dist, a dual install), and both must find the same owner.
|
|
30
|
+
*/
|
|
31
|
+
const RULES = import.meta.env?.DEV || (typeof __OGYGIA_RULES__ !== "undefined" ? __OGYGIA_RULES__ : false);
|
|
32
|
+
const slot = globalThis[Symbol.for("ogygia.request-scope.v1")] ??= { by_request: /* @__PURE__ */ new WeakMap() };
|
|
33
|
+
function entry_of(request) {
|
|
34
|
+
let entry = slot.by_request.get(request);
|
|
35
|
+
if (entry === void 0) {
|
|
36
|
+
const owner = scope();
|
|
37
|
+
const signal = request.signal;
|
|
38
|
+
if (signal.aborted) owner.close();
|
|
39
|
+
else owner.on(signal, "abort", () => end_request_scope(owner));
|
|
40
|
+
entry = {
|
|
41
|
+
owner,
|
|
42
|
+
locals: null
|
|
43
|
+
};
|
|
44
|
+
slot.by_request.set(request, entry);
|
|
45
|
+
}
|
|
46
|
+
return entry;
|
|
47
|
+
}
|
|
48
|
+
/** The owner of `request` (made on first touch). */
|
|
49
|
+
function request_scope(request) {
|
|
50
|
+
return entry_of(request).owner;
|
|
51
|
+
}
|
|
52
|
+
/** The owner of the request the running code belongs to, or null outside one. */
|
|
53
|
+
function current_request_scope() {
|
|
54
|
+
const request = current_request();
|
|
55
|
+
return request ? entry_of(request).owner : null;
|
|
56
|
+
}
|
|
57
|
+
/** A value per request: `make` runs the first time a request asks, and what it made is disposed
|
|
58
|
+
* when that request ends. Asked after the end, it is made and disposed at once. */
|
|
59
|
+
function request_local(make) {
|
|
60
|
+
const key = {};
|
|
61
|
+
return (request) => {
|
|
62
|
+
const entry = entry_of(request);
|
|
63
|
+
let value = entry.locals?.get(key);
|
|
64
|
+
if (value === void 0) {
|
|
65
|
+
value = entry.owner.adopt(make(entry.owner));
|
|
66
|
+
(entry.locals ??= /* @__PURE__ */ new Map()).set(key, value);
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Says that a cleanup of a request's work failed (`request_cleanup_failed`, the error after it):
|
|
72
|
+
* for an ending nobody waits on, such as a stream source ended as the visitor leaves. */
|
|
73
|
+
function cleanup_failed(error) {
|
|
74
|
+
warn("request_cleanup_failed", error);
|
|
75
|
+
}
|
|
76
|
+
/** Ends a request's owner. A cleanup that throws is said, never thrown: the response is not its. */
|
|
77
|
+
function end_request_scope(owner) {
|
|
78
|
+
try {
|
|
79
|
+
owner.close();
|
|
80
|
+
} catch (error) {
|
|
81
|
+
cleanup_failed(error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const noop = () => {};
|
|
85
|
+
/**
|
|
86
|
+
* Will the platform answer `request` with `response` without reading its body? A HEAD answer sends
|
|
87
|
+
* none, and SvelteKit turns a 200 whose etag the visitor already has into a 304 after the handle
|
|
88
|
+
* returns, dropping the body (the same match as its respond: a `W/` prefix on the asked etag
|
|
89
|
+
* ignored). Nobody reads or cancels such a body, so its end would never come.
|
|
90
|
+
*/
|
|
91
|
+
function body_unread(request, response) {
|
|
92
|
+
if (request.method === "HEAD") return true;
|
|
93
|
+
if (response.status !== 200) return false;
|
|
94
|
+
const etag = response.headers.get("etag");
|
|
95
|
+
if (etag === null) return false;
|
|
96
|
+
let asked = request.headers.get("if-none-match");
|
|
97
|
+
if (asked?.startsWith("W/\"")) asked = asked.slice(2);
|
|
98
|
+
return asked === etag;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Core only (the handle): `response` to `request`, whose end ends `owner`. No body, or one the
|
|
102
|
+
* platform will not read (`body_unread`): it ends now. A body: the response carries it through as
|
|
103
|
+
* it is, chunk by chunk, and its last chunk read or its cancel ends the owner; the owner ending
|
|
104
|
+
* first (the visitor left) cancels the body and ends the response.
|
|
105
|
+
*/
|
|
106
|
+
function own_response(owner, response, request) {
|
|
107
|
+
const body = response.body;
|
|
108
|
+
if (body === null || owner.closed) {
|
|
109
|
+
end_request_scope(owner);
|
|
110
|
+
if (RULES) note_response_end(owner);
|
|
111
|
+
return response;
|
|
112
|
+
}
|
|
113
|
+
if (body_unread(request, response)) {
|
|
114
|
+
body.cancel().catch(noop);
|
|
115
|
+
end_request_scope(owner);
|
|
116
|
+
if (RULES) note_response_end(owner);
|
|
117
|
+
return response;
|
|
118
|
+
}
|
|
119
|
+
const reader = body.getReader();
|
|
120
|
+
owner.defer(() => void reader.cancel().catch(noop));
|
|
121
|
+
const carried = new ReadableStream({
|
|
122
|
+
async pull(controller) {
|
|
123
|
+
let step;
|
|
124
|
+
try {
|
|
125
|
+
step = await reader.read();
|
|
126
|
+
} catch (error) {
|
|
127
|
+
end_request_scope(owner);
|
|
128
|
+
if (RULES) note_response_end(owner);
|
|
129
|
+
controller.error(error);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (step.done) {
|
|
133
|
+
controller.close();
|
|
134
|
+
end_request_scope(owner);
|
|
135
|
+
if (RULES) note_response_end(owner);
|
|
136
|
+
} else controller.enqueue(step.value);
|
|
137
|
+
},
|
|
138
|
+
cancel() {
|
|
139
|
+
end_request_scope(owner);
|
|
140
|
+
if (RULES) note_response_end(owner);
|
|
141
|
+
}
|
|
142
|
+
}, { highWaterMark: 0 });
|
|
143
|
+
return new Response(carried, {
|
|
144
|
+
status: response.status,
|
|
145
|
+
statusText: response.statusText,
|
|
146
|
+
headers: response.headers
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
export { cleanup_failed, current_request_scope, end_request_scope, own_response, request_local, request_scope };
|
package/dist/plugin/server.d.ts
CHANGED
|
@@ -17,12 +17,30 @@ export interface LivePlugin {
|
|
|
17
17
|
/** The app's signer, handed in by the handle (it holds the region key, and answers a refused
|
|
18
18
|
* capability the way it answers a refused region request). */
|
|
19
19
|
export type AppSigner = CapabilitySigner;
|
|
20
|
-
/** Make each plugin live, in order: app, shared hooks, `setup`.
|
|
21
|
-
|
|
20
|
+
/** Make each plugin live, in order: app, shared hooks, `setup`. `leave` takes their shared hooks out
|
|
21
|
+
* again. */
|
|
22
|
+
export declare function start_plugins(entries: readonly ServerPluginEntry[], signer: AppSigner): {
|
|
23
|
+
plugins: LivePlugin[];
|
|
24
|
+
leave: () => void;
|
|
25
|
+
};
|
|
26
|
+
/** The app's plugins, live: the handle module's start, each time it runs. The plugins of the run
|
|
27
|
+
* before leave first, so only this run's answer `ask` and hear `notify`. */
|
|
28
|
+
export declare function start_app_plugins(entries: readonly ServerPluginEntry[], signer: AppSigner): LivePlugin[];
|
|
22
29
|
/** Two `resolve()` option sets as one: the inner transform (ogygia's document injection) runs first,
|
|
23
30
|
* the outer (a plugin's `handle`) sees the finished chunk; the other options merge, outer last. */
|
|
24
31
|
export declare function compose_resolve_options(inner?: ResolveOptions, outer?: ResolveOptions): ResolveOptions | undefined;
|
|
25
32
|
/** The plugins' `handle` hooks nested around `core`, first plugin outermost. No hook: `core` itself. */
|
|
26
33
|
export declare function around(plugins: readonly LivePlugin[], core: Handle): Handle;
|
|
34
|
+
/**
|
|
35
|
+
* The request's end: each plugin's `done`, in order (one that throws does not stop the others), and
|
|
36
|
+
* the work they leave running (a sink's send, #243):
|
|
37
|
+
* - the platform keeps a request alive past its response (`platform.context.waitUntil` or
|
|
38
|
+
* `platform.ctx.waitUntil`): the work is handed to it;
|
|
39
|
+
* - otherwise it runs on by itself: a long-running server keeps it alive in the process.
|
|
40
|
+
*
|
|
41
|
+
* The visitor's response is never held for it. A failed piece of work never fails the request (the
|
|
42
|
+
* plugin says what went wrong), and is never an unhandled rejection.
|
|
43
|
+
*/
|
|
44
|
+
export declare function end_request(plugins: readonly LivePlugin[], ctxs: readonly RequestContext<unknown, unknown>[], platform: unknown): void;
|
|
27
45
|
/** The per-plugin contexts of one request. */
|
|
28
46
|
export declare function request_contexts(plugins: readonly LivePlugin[], event: RequestEvent, path: string, facts: RequestFacts, render_hole: (endpoint: string) => Promise<string | null>): RequestContext<unknown, unknown>[];
|
package/dist/plugin/server.js
CHANGED
|
@@ -3,35 +3,57 @@ import { ask, notify, register_hooks } from "./hooks.js";
|
|
|
3
3
|
import { route_config } from "./routes.js";
|
|
4
4
|
import { plugin_capabilities } from "./capability.js";
|
|
5
5
|
import { record_server_event } from "../events/server-registry.js";
|
|
6
|
+
import { warn } from "../messages/server.js";
|
|
7
|
+
import { try_get_request_store } from "@sveltejs/kit/internal/server";
|
|
6
8
|
// src/plugin/server.ts
|
|
7
|
-
/** Make each plugin live, in order: app, shared hooks, `setup`.
|
|
9
|
+
/** Make each plugin live, in order: app, shared hooks, `setup`. `leave` takes their shared hooks out
|
|
10
|
+
* again. */
|
|
8
11
|
function start_plugins(entries, signer) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
app
|
|
33
|
-
|
|
34
|
-
|
|
12
|
+
const leaves = [];
|
|
13
|
+
return {
|
|
14
|
+
plugins: entries.map(({ name, options, server }) => {
|
|
15
|
+
const warned = /* @__PURE__ */ new Set();
|
|
16
|
+
const app = {
|
|
17
|
+
name,
|
|
18
|
+
options,
|
|
19
|
+
notify,
|
|
20
|
+
ask,
|
|
21
|
+
facts: facts_of,
|
|
22
|
+
current: current_facts,
|
|
23
|
+
sign: signer.sign,
|
|
24
|
+
verify: signer.verify,
|
|
25
|
+
capability: plugin_capabilities(name, signer),
|
|
26
|
+
devtools: record_server_event,
|
|
27
|
+
keepAlive: keep_alive,
|
|
28
|
+
warn(message) {
|
|
29
|
+
if (warned.has(message)) return;
|
|
30
|
+
warned.add(message);
|
|
31
|
+
console.warn(`[${name}] ${message}`);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
leaves.push(register_hooks(server));
|
|
35
|
+
server.setup?.(app);
|
|
36
|
+
return {
|
|
37
|
+
def: server,
|
|
38
|
+
app
|
|
39
|
+
};
|
|
40
|
+
}),
|
|
41
|
+
leave() {
|
|
42
|
+
for (const leave of leaves) leave();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** The leave of the app's plugins as the handle module last started them. One global slot, like the
|
|
47
|
+
* shared hooks themselves: the handle module runs again in dev (an edit runs a plugin's server half
|
|
48
|
+
* again, and the handle module that imports it), and its new run must not find the old one there. */
|
|
49
|
+
const app_plugins = globalThis[Symbol.for("ogygia.app-plugins.v1")] ??= { leave: null };
|
|
50
|
+
/** The app's plugins, live: the handle module's start, each time it runs. The plugins of the run
|
|
51
|
+
* before leave first, so only this run's answer `ask` and hear `notify`. */
|
|
52
|
+
function start_app_plugins(entries, signer) {
|
|
53
|
+
app_plugins.leave?.();
|
|
54
|
+
const { plugins, leave } = start_plugins(entries, signer);
|
|
55
|
+
app_plugins.leave = leave;
|
|
56
|
+
return plugins;
|
|
35
57
|
}
|
|
36
58
|
/** Two `resolve()` option sets as one: the inner transform (ogygia's document injection) runs first,
|
|
37
59
|
* the outer (a plugin's `handle`) sees the finished chunk; the other options merge, outer last. */
|
|
@@ -72,6 +94,54 @@ function around(plugins, core) {
|
|
|
72
94
|
}
|
|
73
95
|
return inner;
|
|
74
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* The request's end: each plugin's `done`, in order (one that throws does not stop the others), and
|
|
99
|
+
* the work they leave running (a sink's send, #243):
|
|
100
|
+
* - the platform keeps a request alive past its response (`platform.context.waitUntil` or
|
|
101
|
+
* `platform.ctx.waitUntil`): the work is handed to it;
|
|
102
|
+
* - otherwise it runs on by itself: a long-running server keeps it alive in the process.
|
|
103
|
+
*
|
|
104
|
+
* The visitor's response is never held for it. A failed piece of work never fails the request (the
|
|
105
|
+
* plugin says what went wrong), and is never an unhandled rejection.
|
|
106
|
+
*/
|
|
107
|
+
function end_request(plugins, ctxs, platform) {
|
|
108
|
+
let left = null;
|
|
109
|
+
for (let i = 0; i < plugins.length; i++) try {
|
|
110
|
+
const work = plugins[i].def.done?.(ctxs[i]);
|
|
111
|
+
if (work) (left ??= []).push(Promise.resolve(work).then(void 0, done_failed));
|
|
112
|
+
} catch (error) {
|
|
113
|
+
done_failed(error);
|
|
114
|
+
}
|
|
115
|
+
if (left === null) return;
|
|
116
|
+
const wait_until = wait_until_of(platform);
|
|
117
|
+
if (wait_until === null) return;
|
|
118
|
+
try {
|
|
119
|
+
wait_until(left.length === 1 ? left[0] : Promise.all(left).then(ignore));
|
|
120
|
+
} catch {}
|
|
121
|
+
}
|
|
122
|
+
function done_failed(error) {
|
|
123
|
+
warn("plugin_hook_failed", { name: "done" }, error);
|
|
124
|
+
}
|
|
125
|
+
function ignore() {}
|
|
126
|
+
/** `app.keepAlive`: `work` handed to the `waitUntil` of the request the running code belongs to
|
|
127
|
+
* (Kit's request store knows it, through every await of the request), or left to run on. */
|
|
128
|
+
function keep_alive(work) {
|
|
129
|
+
const event = try_get_request_store()?.event;
|
|
130
|
+
const wait_until = wait_until_of(event?.platform);
|
|
131
|
+
if (wait_until === null) return;
|
|
132
|
+
try {
|
|
133
|
+
wait_until(work);
|
|
134
|
+
} catch {}
|
|
135
|
+
}
|
|
136
|
+
/** The platform's way to keep a request alive past its response, or null. */
|
|
137
|
+
function wait_until_of(platform) {
|
|
138
|
+
if (typeof platform !== "object" || platform === null) return null;
|
|
139
|
+
for (const at of ["context", "ctx"]) {
|
|
140
|
+
const host = platform[at];
|
|
141
|
+
if (typeof host?.waitUntil === "function") return (work) => host.waitUntil(work);
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
75
145
|
/** The per-plugin contexts of one request. */
|
|
76
146
|
function request_contexts(plugins, event, path, facts, render_hole) {
|
|
77
147
|
const route_id = event.route?.id;
|
|
@@ -89,4 +159,4 @@ function request_contexts(plugins, event, path, facts, render_hole) {
|
|
|
89
159
|
perVisitor: per_visitor
|
|
90
160
|
}));
|
|
91
161
|
}
|
|
92
|
-
export { around, compose_resolve_options, request_contexts, start_plugins };
|
|
162
|
+
export { around, compose_resolve_options, end_request, request_contexts, start_app_plugins, start_plugins };
|
package/dist/plugin/testing.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { RequestContext, ServerApp, ServerPlugin } from "./index.js";
|
|
2
2
|
import { clear_route_config, route_config, set_page_route_config } from "./routes.js";
|
|
3
3
|
import { RequestEvent } from "@sveltejs/kit";
|
|
4
|
+
/**
|
|
5
|
+
* Runs `fn` inside a request, as Kit runs a hook or an endpoint: Kit's request store carries
|
|
6
|
+
* `event` through every await of it, so `app.keepAlive` finds its platform (a `waitUntil` at
|
|
7
|
+
* `platform.context` or `platform.ctx`).
|
|
8
|
+
*/
|
|
9
|
+
export declare function inRequest<T>(event: Partial<RequestEvent>, fn: () => T): T;
|
|
4
10
|
export interface StartedPlugin<Options, State> {
|
|
5
11
|
app: ServerApp<Options>;
|
|
6
12
|
/** A request context for `request` (a bare event: url, request, cookies that read nothing). */
|
package/dist/plugin/testing.js
CHANGED
|
@@ -3,6 +3,7 @@ import { request_contexts, start_plugins } from "./server.js";
|
|
|
3
3
|
import { capability_lifetime } from "../server/capability-lifetime.js";
|
|
4
4
|
import { RENEW_WINDOW_SEC } from "../server/shared-cache.js";
|
|
5
5
|
import { clear_route_config, route_config, set_page_route_config } from "./routes.js";
|
|
6
|
+
import { with_request_store } from "@sveltejs/kit/internal/server";
|
|
6
7
|
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
7
8
|
// src/plugin/testing.ts
|
|
8
9
|
/** A real HMAC under a key made for this test process. */
|
|
@@ -25,8 +26,19 @@ const TEST_SIGNER = {
|
|
|
25
26
|
headers: { "x-ogygia-deny": why }
|
|
26
27
|
})
|
|
27
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* Runs `fn` inside a request, as Kit runs a hook or an endpoint: Kit's request store carries
|
|
31
|
+
* `event` through every await of it, so `app.keepAlive` finds its platform (a `waitUntil` at
|
|
32
|
+
* `platform.context` or `platform.ctx`).
|
|
33
|
+
*/
|
|
34
|
+
function inRequest(event, fn) {
|
|
35
|
+
return with_request_store({
|
|
36
|
+
event,
|
|
37
|
+
state: {}
|
|
38
|
+
}, fn);
|
|
39
|
+
}
|
|
28
40
|
function startPlugin(server, { name = "test-plugin", options } = {}) {
|
|
29
|
-
const [live] = start_plugins([{
|
|
41
|
+
const { plugins: [live] } = start_plugins([{
|
|
30
42
|
name,
|
|
31
43
|
options,
|
|
32
44
|
server
|
|
@@ -51,4 +63,4 @@ function startPlugin(server, { name = "test-plugin", options } = {}) {
|
|
|
51
63
|
}
|
|
52
64
|
};
|
|
53
65
|
}
|
|
54
|
-
export { clear_route_config as clearRouteConfig, route_config as routeConfig, set_page_route_config as setPageRouteConfig, startPlugin };
|
|
66
|
+
export { clear_route_config as clearRouteConfig, inRequest, route_config as routeConfig, set_page_route_config as setPageRouteConfig, startPlugin };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Policy } from "@ogygia/machine";
|
|
2
|
+
/** A lazy chunk of the runtime (the hydrate core, the navigation chunk, devalue): one more try at
|
|
3
|
+
* once when its download fails, under a fresh URL (`import_again`). A dropped download is usually
|
|
4
|
+
* a blip; a second failure is a real outage, and the caller's own recovery takes over. */
|
|
5
|
+
export declare const download: Policy;
|
|
6
|
+
/** devalue's download for a read that runs once (a streamed value's resolver): asked for again
|
|
7
|
+
* after 1, 2, 4 and 8 s, then left (the network is down; the reads wait, as before). */
|
|
8
|
+
export declare const devalue_download: Policy;
|
|
9
|
+
/** A hole's fetch of its region: three tries, 0.5 s then 1 s apart, before it keeps its fallback.
|
|
10
|
+
* Long enough for a server restart's blip, short enough that a broken hole settles fast. */
|
|
11
|
+
export declare const region_fetch: Policy;
|
|
12
|
+
/** A region's server render, its wait for a render slot included: one try within 10 s (#195). A
|
|
13
|
+
* render stuck on a hung upstream past it is abandoned, so it never holds a slot for good. */
|
|
14
|
+
export declare const render: Policy;
|
|
15
|
+
/** A batch stream of holes: given up after 10 s with no bytes (#214). The server sends a hole's part
|
|
16
|
+
* only once it has rendered, so a few quiet seconds are a slow render, not a dead stream; the
|
|
17
|
+
* `render` deadline bounds each render, so a stream quiet for as long is dead. */
|
|
18
|
+
export declare const stream: Policy;
|
|
19
|
+
/** An island file's recovery during a deploy's rollover: the current build's map asked at once,
|
|
20
|
+
* then after 1, 3 and 9 s while it settles (a rollover settles in seconds). */
|
|
21
|
+
export declare const rollover: Policy;
|