vorma 0.0.0-pre.0 → 0.83.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/LICENSE +28 -0
- package/README.md +48 -0
- package/internal/framework/_typescript/client/index.ts +64 -0
- package/internal/framework/_typescript/client/src/asset_manager.ts +67 -0
- package/internal/framework/_typescript/client/src/client.ts +1201 -0
- package/internal/framework/_typescript/client/src/client_loaders.ts +249 -0
- package/internal/framework/_typescript/client/src/component_loader.ts +105 -0
- package/internal/framework/_typescript/client/src/error_boundary.ts +7 -0
- package/internal/framework/_typescript/client/src/events.ts +54 -0
- package/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.ts +125 -0
- package/internal/framework/_typescript/client/src/hard_reload.ts +1 -0
- package/internal/framework/_typescript/client/src/head_elements/head_elements.ts +193 -0
- package/internal/framework/_typescript/client/src/history/history.ts +118 -0
- package/internal/framework/_typescript/client/src/history/npm_history_types.ts +83 -0
- package/internal/framework/_typescript/client/src/hmr/hmr.ts +71 -0
- package/internal/framework/_typescript/client/src/init_client.ts +134 -0
- package/internal/framework/_typescript/client/src/links.ts +218 -0
- package/internal/framework/_typescript/client/src/redirects/redirects.ts +203 -0
- package/internal/framework/_typescript/client/src/rendering.ts +135 -0
- package/internal/framework/_typescript/client/src/resolve_public_href.ts +15 -0
- package/internal/framework/_typescript/client/src/scroll_state_manager.ts +100 -0
- package/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.ts +22 -0
- package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.ts +131 -0
- package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.ts +56 -0
- package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.ts +58 -0
- package/internal/framework/_typescript/client/src/utils/errors.ts +10 -0
- package/internal/framework/_typescript/client/src/utils/logging.ts +7 -0
- package/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.ts +290 -0
- package/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.ts +128 -0
- package/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.ts +32 -0
- package/internal/framework/_typescript/client/tsconfig.json +3 -0
- package/internal/framework/_typescript/create/main.ts +378 -0
- package/internal/framework/_typescript/create/package.json +33 -0
- package/internal/framework/_typescript/create/pnpm-lock.yaml +70 -0
- package/internal/framework/_typescript/create/tsconfig.json +3 -0
- package/internal/framework/_typescript/preact/index.tsx +10 -0
- package/internal/framework/_typescript/preact/src/helpers.ts +113 -0
- package/internal/framework/_typescript/preact/src/link.tsx +107 -0
- package/internal/framework/_typescript/preact/src/preact.tsx +191 -0
- package/internal/framework/_typescript/preact/tsconfig.json +7 -0
- package/internal/framework/_typescript/react/index.tsx +10 -0
- package/internal/framework/_typescript/react/src/helpers.ts +118 -0
- package/internal/framework/_typescript/react/src/link.tsx +115 -0
- package/internal/framework/_typescript/react/src/react.tsx +299 -0
- package/internal/framework/_typescript/react/tsconfig.json +6 -0
- package/internal/framework/_typescript/solid/index.tsx +10 -0
- package/internal/framework/_typescript/solid/src/helpers.ts +114 -0
- package/internal/framework/_typescript/solid/src/link.tsx +104 -0
- package/internal/framework/_typescript/solid/src/solid.tsx +204 -0
- package/internal/framework/_typescript/solid/tsconfig.json +7 -0
- package/internal/framework/_typescript/vite/tsconfig.json +3 -0
- package/internal/framework/_typescript/vite/vite.ts +93 -0
- package/internal/site/frontend/assets/vorma-banner.webp +0 -0
- package/kit/_typescript/converters/converters.ts +152 -0
- package/kit/_typescript/cookies/cookies.ts +18 -0
- package/kit/_typescript/csrf/csrf.ts +10 -0
- package/kit/_typescript/debounce/debounce.ts +17 -0
- package/kit/_typescript/fmt/fmt.ts +3 -0
- package/kit/_typescript/json/deep_equals.ts +54 -0
- package/kit/_typescript/json/json.ts +3 -0
- package/kit/_typescript/json/search_param_serializer.ts +49 -0
- package/kit/_typescript/json/stringify_stable.ts +43 -0
- package/kit/_typescript/listeners/listeners.ts +16 -0
- package/kit/_typescript/matcher/find_best_match.ts +205 -0
- package/kit/_typescript/matcher/find_nested_matches.ts +357 -0
- package/kit/_typescript/matcher/parse_segments.ts +30 -0
- package/kit/_typescript/matcher/register.ts +271 -0
- package/kit/_typescript/theme/theme.ts +177 -0
- package/kit/_typescript/tsconfig.json +3 -0
- package/kit/_typescript/url/url.ts +132 -0
- package/npm_dist/internal/framework/_typescript/client/index.d.ts +17 -0
- package/npm_dist/internal/framework/_typescript/client/index.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/index.js +2489 -0
- package/npm_dist/internal/framework/_typescript/client/index.js.map +7 -0
- package/npm_dist/internal/framework/_typescript/client/src/asset_manager.d.ts +6 -0
- package/npm_dist/internal/framework/_typescript/client/src/asset_manager.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/client.d.ts +119 -0
- package/npm_dist/internal/framework/_typescript/client/src/client.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/client_loaders.d.ts +18 -0
- package/npm_dist/internal/framework/_typescript/client/src/client_loaders.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/component_loader.d.ts +10 -0
- package/npm_dist/internal/framework/_typescript/client/src/component_loader.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/error_boundary.d.ts +3 -0
- package/npm_dist/internal/framework/_typescript/client/src/error_boundary.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/events.d.ts +26 -0
- package/npm_dist/internal/framework/_typescript/client/src/events.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.d.ts +12 -0
- package/npm_dist/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/hard_reload.d.ts +2 -0
- package/npm_dist/internal/framework/_typescript/client/src/hard_reload.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/head_elements/head_elements.d.ts +7 -0
- package/npm_dist/internal/framework/_typescript/client/src/head_elements/head_elements.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/history/history.d.ts +14 -0
- package/npm_dist/internal/framework/_typescript/client/src/history/history.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/history/npm_history_types.d.ts +84 -0
- package/npm_dist/internal/framework/_typescript/client/src/history/npm_history_types.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/hmr/hmr.d.ts +3 -0
- package/npm_dist/internal/framework/_typescript/client/src/hmr/hmr.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/init_client.d.ts +9 -0
- package/npm_dist/internal/framework/_typescript/client/src/init_client.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/links.d.ts +33 -0
- package/npm_dist/internal/framework/_typescript/client/src/links.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/redirects/redirects.d.ts +26 -0
- package/npm_dist/internal/framework/_typescript/client/src/redirects/redirects.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/rendering.d.ts +18 -0
- package/npm_dist/internal/framework/_typescript/client/src/rendering.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/resolve_public_href.d.ts +2 -0
- package/npm_dist/internal/framework/_typescript/client/src/resolve_public_href.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/scroll_state_manager.d.ts +22 -0
- package/npm_dist/internal/framework/_typescript/client/src/scroll_state_manager.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.d.ts +12 -0
- package/npm_dist/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.d.ts +28 -0
- package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.d.ts +18 -0
- package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.d.ts +11 -0
- package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/utils/errors.d.ts +3 -0
- package/npm_dist/internal/framework/_typescript/client/src/utils/errors.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/utils/logging.d.ts +3 -0
- package/npm_dist/internal/framework/_typescript/client/src/utils/logging.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.d.ts +119 -0
- package/npm_dist/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.d.ts +88 -0
- package/npm_dist/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.d.ts +10 -0
- package/npm_dist/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/create/main.d.ts +3 -0
- package/npm_dist/internal/framework/_typescript/create/main.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/preact/index.d.ts +4 -0
- package/npm_dist/internal/framework/_typescript/preact/index.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/preact/index.js +283 -0
- package/npm_dist/internal/framework/_typescript/preact/index.js.map +7 -0
- package/npm_dist/internal/framework/_typescript/preact/src/helpers.d.ts +21 -0
- package/npm_dist/internal/framework/_typescript/preact/src/helpers.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/preact/src/link.d.ts +11 -0
- package/npm_dist/internal/framework/_typescript/preact/src/link.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/preact/src/preact.d.ts +21 -0
- package/npm_dist/internal/framework/_typescript/preact/src/preact.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/react/index.d.ts +4 -0
- package/npm_dist/internal/framework/_typescript/react/index.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/react/index.js +370 -0
- package/npm_dist/internal/framework/_typescript/react/index.js.map +7 -0
- package/npm_dist/internal/framework/_typescript/react/src/helpers.d.ts +21 -0
- package/npm_dist/internal/framework/_typescript/react/src/helpers.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/react/src/link.d.ts +11 -0
- package/npm_dist/internal/framework/_typescript/react/src/link.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/react/src/react.d.ts +20 -0
- package/npm_dist/internal/framework/_typescript/react/src/react.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/solid/index.d.ts +4 -0
- package/npm_dist/internal/framework/_typescript/solid/index.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/solid/index.js +314 -0
- package/npm_dist/internal/framework/_typescript/solid/index.js.map +7 -0
- package/npm_dist/internal/framework/_typescript/solid/src/helpers.d.ts +22 -0
- package/npm_dist/internal/framework/_typescript/solid/src/helpers.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/solid/src/link.d.ts +11 -0
- package/npm_dist/internal/framework/_typescript/solid/src/link.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/solid/src/solid.d.ts +22 -0
- package/npm_dist/internal/framework/_typescript/solid/src/solid.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/vite/vite.d.ts +11 -0
- package/npm_dist/internal/framework/_typescript/vite/vite.d.ts.map +1 -0
- package/npm_dist/internal/framework/_typescript/vite/vite.js +82 -0
- package/npm_dist/internal/framework/_typescript/vite/vite.js.map +7 -0
- package/npm_dist/kit/_typescript/chunk-YBAPNBS2.js +202 -0
- package/npm_dist/kit/_typescript/chunk-YBAPNBS2.js.map +7 -0
- package/npm_dist/kit/_typescript/converters/converters.d.ts +26 -0
- package/npm_dist/kit/_typescript/converters/converters.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/converters/converters.js +99 -0
- package/npm_dist/kit/_typescript/converters/converters.js.map +7 -0
- package/npm_dist/kit/_typescript/cookies/cookies.d.ts +13 -0
- package/npm_dist/kit/_typescript/cookies/cookies.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/cookies/cookies.js +13 -0
- package/npm_dist/kit/_typescript/cookies/cookies.js.map +7 -0
- package/npm_dist/kit/_typescript/csrf/csrf.d.ts +5 -0
- package/npm_dist/kit/_typescript/csrf/csrf.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/csrf/csrf.js +11 -0
- package/npm_dist/kit/_typescript/csrf/csrf.js.map +7 -0
- package/npm_dist/kit/_typescript/debounce/debounce.d.ts +4 -0
- package/npm_dist/kit/_typescript/debounce/debounce.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/debounce/debounce.js +16 -0
- package/npm_dist/kit/_typescript/debounce/debounce.js.map +7 -0
- package/npm_dist/kit/_typescript/fmt/fmt.d.ts +2 -0
- package/npm_dist/kit/_typescript/fmt/fmt.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/fmt/fmt.js +8 -0
- package/npm_dist/kit/_typescript/fmt/fmt.js.map +7 -0
- package/npm_dist/kit/_typescript/json/deep_equals.d.ts +7 -0
- package/npm_dist/kit/_typescript/json/deep_equals.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/json/json.d.ts +4 -0
- package/npm_dist/kit/_typescript/json/json.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/json/json.js +110 -0
- package/npm_dist/kit/_typescript/json/json.js.map +7 -0
- package/npm_dist/kit/_typescript/json/search_param_serializer.d.ts +2 -0
- package/npm_dist/kit/_typescript/json/search_param_serializer.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/json/stringify_stable.d.ts +7 -0
- package/npm_dist/kit/_typescript/json/stringify_stable.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/listeners/listeners.d.ts +2 -0
- package/npm_dist/kit/_typescript/listeners/listeners.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/listeners/listeners.js +20 -0
- package/npm_dist/kit/_typescript/listeners/listeners.js.map +7 -0
- package/npm_dist/kit/_typescript/matcher/find_best_match.d.ts +10 -0
- package/npm_dist/kit/_typescript/matcher/find_best_match.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/matcher/find_best_match.js +146 -0
- package/npm_dist/kit/_typescript/matcher/find_best_match.js.map +7 -0
- package/npm_dist/kit/_typescript/matcher/find_nested_matches.d.ts +14 -0
- package/npm_dist/kit/_typescript/matcher/find_nested_matches.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/matcher/find_nested_matches.js +248 -0
- package/npm_dist/kit/_typescript/matcher/find_nested_matches.js.map +7 -0
- package/npm_dist/kit/_typescript/matcher/parse_segments.d.ts +2 -0
- package/npm_dist/kit/_typescript/matcher/parse_segments.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/matcher/register.d.ts +54 -0
- package/npm_dist/kit/_typescript/matcher/register.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/matcher/register.js +21 -0
- package/npm_dist/kit/_typescript/matcher/register.js.map +7 -0
- package/npm_dist/kit/_typescript/theme/theme.d.ts +24 -0
- package/npm_dist/kit/_typescript/theme/theme.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/theme/theme.js +133 -0
- package/npm_dist/kit/_typescript/theme/theme.js.map +7 -0
- package/npm_dist/kit/_typescript/url/url.d.ts +30 -0
- package/npm_dist/kit/_typescript/url/url.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/url/url.js +100 -0
- package/npm_dist/kit/_typescript/url/url.js.map +7 -0
- package/package.json +135 -3
- package/tsconfig.base.json +17 -0
- package/index.js +0 -1
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { findNestedMatches } from "vorma/kit/matcher/find-nested";
|
|
2
|
+
import { registerPattern } from "vorma/kit/matcher/register";
|
|
3
|
+
import { ComponentLoader, getEffectiveErrorData } from "./component_loader.ts";
|
|
4
|
+
import { isAbortError } from "./utils/errors.ts";
|
|
5
|
+
import { logError } from "./utils/logging.ts";
|
|
6
|
+
import {
|
|
7
|
+
__vormaClientGlobal,
|
|
8
|
+
type GetRouteDataOutput,
|
|
9
|
+
} from "./vorma_ctx/vorma_ctx.ts";
|
|
10
|
+
|
|
11
|
+
export function setClientLoadersState(
|
|
12
|
+
clr: ClientLoadersResult | undefined,
|
|
13
|
+
): void {
|
|
14
|
+
if (clr) {
|
|
15
|
+
__vormaClientGlobal.set("clientLoadersData", clr.data ?? []);
|
|
16
|
+
__vormaClientGlobal.set(
|
|
17
|
+
"outermostClientErrorIdx",
|
|
18
|
+
clr.errorMessage ? clr.data.length - 1 : undefined,
|
|
19
|
+
);
|
|
20
|
+
__vormaClientGlobal.set("outermostClientError", clr.errorMessage);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function deriveAndSetErrorState(): void {
|
|
25
|
+
const effectiveErrData = getEffectiveErrorData();
|
|
26
|
+
__vormaClientGlobal.set("outermostErrorIdx", effectiveErrData.index);
|
|
27
|
+
__vormaClientGlobal.set("outermostError", effectiveErrData.error);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function setupClientLoaders(): Promise<void> {
|
|
31
|
+
const clientLoadersResult = await runWaitFns(
|
|
32
|
+
{
|
|
33
|
+
hasRootData: __vormaClientGlobal.get("hasRootData"),
|
|
34
|
+
importURLs: __vormaClientGlobal.get("importURLs"),
|
|
35
|
+
loadersData: __vormaClientGlobal.get("loadersData"),
|
|
36
|
+
matchedPatterns: __vormaClientGlobal.get("matchedPatterns"),
|
|
37
|
+
params: __vormaClientGlobal.get("params"),
|
|
38
|
+
splatValues: __vormaClientGlobal.get("splatValues"),
|
|
39
|
+
},
|
|
40
|
+
__vormaClientGlobal.get("buildID"),
|
|
41
|
+
new AbortController().signal,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
setClientLoadersState(clientLoadersResult);
|
|
45
|
+
deriveAndSetErrorState();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function __registerClientLoaderPattern(
|
|
49
|
+
pattern: string,
|
|
50
|
+
): Promise<void> {
|
|
51
|
+
registerPattern(__vormaClientGlobal.get("patternRegistry"), pattern);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// This is needed because the matcher, by definition, will only
|
|
55
|
+
// match when you have a full path match. If the path you are
|
|
56
|
+
// testing is longer than the registered patterns, you will get
|
|
57
|
+
// no match, even if some registered patterns would potentially
|
|
58
|
+
// be in the parent segments. This fixes that.
|
|
59
|
+
export async function findPartialMatchesOnClient(pathname: string) {
|
|
60
|
+
const patternToWaitFnMap = __vormaClientGlobal.get("patternToWaitFnMap");
|
|
61
|
+
if (Object.keys(patternToWaitFnMap).length === 0) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const patternRegistry = __vormaClientGlobal.get("patternRegistry");
|
|
66
|
+
|
|
67
|
+
// First try the full path
|
|
68
|
+
const fullResult = findNestedMatches(patternRegistry, pathname);
|
|
69
|
+
if (fullResult) {
|
|
70
|
+
// If we get a full match, we have everything we need
|
|
71
|
+
return fullResult;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// If no full match, try progressively shorter paths to find partial matches
|
|
75
|
+
const segments = pathname.split("/").filter(Boolean);
|
|
76
|
+
|
|
77
|
+
// Try from longest to shortest
|
|
78
|
+
for (let i = segments.length; i >= 0; i--) {
|
|
79
|
+
const partialPath =
|
|
80
|
+
i === 0 ? "/" : "/" + segments.slice(0, i).join("/");
|
|
81
|
+
const result = findNestedMatches(patternRegistry, partialPath);
|
|
82
|
+
if (result) {
|
|
83
|
+
return result; // First match is the longest
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type PartialWaitFnJSON = Pick<
|
|
91
|
+
GetRouteDataOutput,
|
|
92
|
+
| "matchedPatterns"
|
|
93
|
+
| "splatValues"
|
|
94
|
+
| "params"
|
|
95
|
+
| "hasRootData"
|
|
96
|
+
| "loadersData"
|
|
97
|
+
| "importURLs"
|
|
98
|
+
>;
|
|
99
|
+
|
|
100
|
+
export type ClientLoadersResult = {
|
|
101
|
+
data: Array<any>;
|
|
102
|
+
errorMessage?: string;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
async function executeClientLoaders(
|
|
106
|
+
json: PartialWaitFnJSON,
|
|
107
|
+
buildID: string,
|
|
108
|
+
signal: AbortSignal,
|
|
109
|
+
runningLoaders?: Map<string, Promise<any>>,
|
|
110
|
+
): Promise<ClientLoadersResult> {
|
|
111
|
+
await ComponentLoader.loadComponents(json.importURLs);
|
|
112
|
+
|
|
113
|
+
const matchedPatterns = json.matchedPatterns ?? [];
|
|
114
|
+
const patternToWaitFnMap = __vormaClientGlobal.get("patternToWaitFnMap");
|
|
115
|
+
const outermostServerErrorIdx = __vormaClientGlobal.get(
|
|
116
|
+
"outermostServerErrorIdx",
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const loaderPromises: Array<Promise<any>> = [];
|
|
120
|
+
const abortControllers: Array<AbortController | null> = [];
|
|
121
|
+
|
|
122
|
+
// Build arrays of all promises and their corresponding abort controllers
|
|
123
|
+
let i = 0;
|
|
124
|
+
for (const pattern of matchedPatterns) {
|
|
125
|
+
if (
|
|
126
|
+
outermostServerErrorIdx !== undefined &&
|
|
127
|
+
i === outermostServerErrorIdx
|
|
128
|
+
) {
|
|
129
|
+
// This route has a server error, skip its client loader
|
|
130
|
+
loaderPromises.push(Promise.resolve());
|
|
131
|
+
abortControllers.push(null);
|
|
132
|
+
i++;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (runningLoaders?.has(pattern)) {
|
|
137
|
+
// This loader is already running (started parallel to fetch)
|
|
138
|
+
loaderPromises.push(runningLoaders.get(pattern)!);
|
|
139
|
+
// We can't create a new controller for it, but we can wrap it
|
|
140
|
+
abortControllers.push(null);
|
|
141
|
+
} else if (patternToWaitFnMap[pattern]) {
|
|
142
|
+
// This is a new client loader we need to run
|
|
143
|
+
const controller = new AbortController();
|
|
144
|
+
abortControllers.push(controller);
|
|
145
|
+
|
|
146
|
+
// Wire up the main navigation signal to this loader's controller
|
|
147
|
+
if (signal.aborted) {
|
|
148
|
+
controller.abort();
|
|
149
|
+
} else {
|
|
150
|
+
signal.addEventListener("abort", () => controller.abort(), {
|
|
151
|
+
once: true,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const serverDataPromise = Promise.resolve({
|
|
156
|
+
matchedPatterns: json.matchedPatterns,
|
|
157
|
+
loaderData: json.loadersData[i],
|
|
158
|
+
rootData: json.hasRootData ? json.loadersData[0] : null,
|
|
159
|
+
buildID: buildID,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const loaderPromise = patternToWaitFnMap[pattern]({
|
|
163
|
+
params: json.params || {},
|
|
164
|
+
splatValues: json.splatValues || [],
|
|
165
|
+
serverDataPromise,
|
|
166
|
+
signal: controller.signal,
|
|
167
|
+
});
|
|
168
|
+
loaderPromises.push(loaderPromise);
|
|
169
|
+
} else {
|
|
170
|
+
// No client loader for this route
|
|
171
|
+
loaderPromises.push(Promise.resolve());
|
|
172
|
+
abortControllers.push(null);
|
|
173
|
+
}
|
|
174
|
+
i++;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Wrap all promises with the child-aborting logic
|
|
178
|
+
const wrappedPromises = loaderPromises.map(async (promise, index) => {
|
|
179
|
+
return promise.catch((error) => {
|
|
180
|
+
// If this promise failed with a true error (not just an abort)
|
|
181
|
+
if (!isAbortError(error)) {
|
|
182
|
+
// Abort all subsequent (child) loaders immediately
|
|
183
|
+
for (let j = index + 1; j < abortControllers.length; j++) {
|
|
184
|
+
abortControllers[j]?.abort();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Re-throw the error so Promise.allSettled sees it as 'rejected'
|
|
188
|
+
throw error;
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Await all wrapped promises. They run in parallel,
|
|
193
|
+
// but a rejection in one now triggers aborts in its children.
|
|
194
|
+
const results = await Promise.allSettled(wrappedPromises);
|
|
195
|
+
|
|
196
|
+
// Process the results
|
|
197
|
+
const data: Array<any> = [];
|
|
198
|
+
let errorMessage: string | undefined;
|
|
199
|
+
|
|
200
|
+
for (let i = 0; i < results.length; i++) {
|
|
201
|
+
const result = results[i];
|
|
202
|
+
if (!result) {
|
|
203
|
+
data.push(undefined);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (result.status === "fulfilled") {
|
|
208
|
+
data.push(result.value);
|
|
209
|
+
} else {
|
|
210
|
+
// This is a rejection
|
|
211
|
+
if (!isAbortError(result.reason)) {
|
|
212
|
+
// This is the first true error we've hit
|
|
213
|
+
const pattern = matchedPatterns[i];
|
|
214
|
+
logError(
|
|
215
|
+
`Client loader error for pattern ${pattern}:`,
|
|
216
|
+
result.reason,
|
|
217
|
+
);
|
|
218
|
+
errorMessage =
|
|
219
|
+
result.reason instanceof Error
|
|
220
|
+
? result.reason.message
|
|
221
|
+
: String(result.reason);
|
|
222
|
+
|
|
223
|
+
// We found the highest error. Stop processing.
|
|
224
|
+
// The .catch() wrapper already aborted any children.
|
|
225
|
+
}
|
|
226
|
+
data.push(undefined);
|
|
227
|
+
break; // Stop at the first error
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return { data, errorMessage };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function runWaitFns(
|
|
235
|
+
json: PartialWaitFnJSON,
|
|
236
|
+
buildID: string,
|
|
237
|
+
signal: AbortSignal,
|
|
238
|
+
): Promise<ClientLoadersResult> {
|
|
239
|
+
return executeClientLoaders(json, buildID, signal);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export async function completeClientLoaders(
|
|
243
|
+
json: PartialWaitFnJSON,
|
|
244
|
+
buildID: string,
|
|
245
|
+
runningLoaders: Map<string, Promise<any>>,
|
|
246
|
+
signal: AbortSignal,
|
|
247
|
+
): Promise<ClientLoadersResult> {
|
|
248
|
+
return executeClientLoaders(json, buildID, signal, runningLoaders);
|
|
249
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { jsonDeepEquals } from "vorma/kit/json";
|
|
2
|
+
import { resolvePublicHref } from "./resolve_public_href.ts";
|
|
3
|
+
import { __vormaClientGlobal } from "./vorma_ctx/vorma_ctx.ts";
|
|
4
|
+
|
|
5
|
+
export function getEffectiveErrorData(): {
|
|
6
|
+
index: number | undefined;
|
|
7
|
+
error: string | undefined;
|
|
8
|
+
} {
|
|
9
|
+
const serverErrorIdx = __vormaClientGlobal.get("outermostServerErrorIdx");
|
|
10
|
+
const clientErrorIdx = __vormaClientGlobal.get("outermostClientErrorIdx");
|
|
11
|
+
let errorIdx: number | undefined;
|
|
12
|
+
if (serverErrorIdx != null && clientErrorIdx != null) {
|
|
13
|
+
errorIdx = Math.min(serverErrorIdx, clientErrorIdx);
|
|
14
|
+
} else {
|
|
15
|
+
errorIdx = serverErrorIdx ?? clientErrorIdx;
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
index: errorIdx,
|
|
19
|
+
error:
|
|
20
|
+
errorIdx === serverErrorIdx
|
|
21
|
+
? __vormaClientGlobal.get("outermostServerError")
|
|
22
|
+
: errorIdx === clientErrorIdx
|
|
23
|
+
? __vormaClientGlobal.get("outermostClientError")
|
|
24
|
+
: undefined,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class ComponentLoader {
|
|
29
|
+
static async loadComponents(
|
|
30
|
+
importURLs: string[],
|
|
31
|
+
): Promise<Map<string, any>> {
|
|
32
|
+
const dedupedURLs = [...new Set(importURLs)];
|
|
33
|
+
const modules = await Promise.all(
|
|
34
|
+
dedupedURLs.map(async (url) => {
|
|
35
|
+
if (!url) return undefined;
|
|
36
|
+
return import(/* @vite-ignore */ resolvePublicHref(url));
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
return new Map(dedupedURLs.map((url, i) => [url, modules[i]]));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static async handleComponents(importURLs: string[]): Promise<void> {
|
|
43
|
+
const modulesMap = await this.loadComponents(importURLs);
|
|
44
|
+
const originalImportURLs = __vormaClientGlobal.get("importURLs");
|
|
45
|
+
const exportKeys = __vormaClientGlobal.get("exportKeys") ?? [];
|
|
46
|
+
|
|
47
|
+
// Build new components array
|
|
48
|
+
const newActiveComponents = originalImportURLs.map(
|
|
49
|
+
(url: string, i: number) => {
|
|
50
|
+
const module = modulesMap.get(url);
|
|
51
|
+
const key = exportKeys[i] ?? "default";
|
|
52
|
+
return module?.[key] ?? null;
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// Only update if components actually changed
|
|
57
|
+
if (
|
|
58
|
+
!jsonDeepEquals(
|
|
59
|
+
newActiveComponents,
|
|
60
|
+
__vormaClientGlobal.get("activeComponents"),
|
|
61
|
+
)
|
|
62
|
+
) {
|
|
63
|
+
__vormaClientGlobal.set("activeComponents", newActiveComponents);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static async handleErrorBoundaryComponent(
|
|
68
|
+
importURLs: string[],
|
|
69
|
+
): Promise<void> {
|
|
70
|
+
const modulesMap = await this.loadComponents(importURLs);
|
|
71
|
+
const originalImportURLs = __vormaClientGlobal.get("importURLs");
|
|
72
|
+
|
|
73
|
+
// Handle error boundary
|
|
74
|
+
const errorIdx = getEffectiveErrorData().index;
|
|
75
|
+
|
|
76
|
+
if (errorIdx != null) {
|
|
77
|
+
const errorModuleURL = originalImportURLs[errorIdx];
|
|
78
|
+
let errorComponent;
|
|
79
|
+
|
|
80
|
+
if (errorModuleURL) {
|
|
81
|
+
const errorModule = modulesMap.get(errorModuleURL);
|
|
82
|
+
const errorKeys = __vormaClientGlobal.get("errorExportKeys");
|
|
83
|
+
const errorKey = errorKeys ? errorKeys[errorIdx] : null;
|
|
84
|
+
if (errorKey && errorModule) {
|
|
85
|
+
errorComponent = errorModule[errorKey];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const newErrorBoundary =
|
|
90
|
+
errorComponent ??
|
|
91
|
+
__vormaClientGlobal.get("defaultErrorBoundary");
|
|
92
|
+
|
|
93
|
+
// Only update if changed
|
|
94
|
+
const currentErrorBoundary = __vormaClientGlobal.get(
|
|
95
|
+
"activeErrorBoundary",
|
|
96
|
+
);
|
|
97
|
+
if (currentErrorBoundary !== newErrorBoundary) {
|
|
98
|
+
__vormaClientGlobal.set(
|
|
99
|
+
"activeErrorBoundary",
|
|
100
|
+
newErrorBoundary,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ScrollState } from "./scroll_state_manager.ts";
|
|
2
|
+
|
|
3
|
+
// Route Change Event
|
|
4
|
+
export const VORMA_ROUTE_CHANGE_EVENT_KEY = "vorma:route-change";
|
|
5
|
+
export type RouteChangeEvent = CustomEvent<RouteChangeEventDetail>;
|
|
6
|
+
export type RouteChangeEventDetail = { __scrollState?: ScrollState };
|
|
7
|
+
export const addRouteChangeListener = makeListenerAdder<RouteChangeEventDetail>(
|
|
8
|
+
VORMA_ROUTE_CHANGE_EVENT_KEY,
|
|
9
|
+
);
|
|
10
|
+
export function dispatchRouteChangeEvent(detail: RouteChangeEventDetail): void {
|
|
11
|
+
window.dispatchEvent(
|
|
12
|
+
new CustomEvent(VORMA_ROUTE_CHANGE_EVENT_KEY, { detail }),
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Status Event
|
|
17
|
+
const STATUS_EVENT_KEY = "vorma:status";
|
|
18
|
+
export type StatusEvent = CustomEvent<StatusEventDetail>;
|
|
19
|
+
export type StatusEventDetail = {
|
|
20
|
+
isNavigating: boolean;
|
|
21
|
+
isSubmitting: boolean;
|
|
22
|
+
isRevalidating: boolean;
|
|
23
|
+
};
|
|
24
|
+
export function dispatchStatusEvent(detail: StatusEventDetail): void {
|
|
25
|
+
window.dispatchEvent(new CustomEvent(STATUS_EVENT_KEY, { detail }));
|
|
26
|
+
}
|
|
27
|
+
export const addStatusListener =
|
|
28
|
+
makeListenerAdder<StatusEventDetail>(STATUS_EVENT_KEY);
|
|
29
|
+
|
|
30
|
+
// Build ID Event
|
|
31
|
+
const BUILD_ID_EVENT_KEY = "vorma:build-id";
|
|
32
|
+
type BuildIDEventDetail = { oldID: string; newID: string };
|
|
33
|
+
export function dispatchBuildIDEvent(detail: BuildIDEventDetail): void {
|
|
34
|
+
window.dispatchEvent(new CustomEvent(BUILD_ID_EVENT_KEY, { detail }));
|
|
35
|
+
}
|
|
36
|
+
export const addBuildIDListener =
|
|
37
|
+
makeListenerAdder<BuildIDEventDetail>(BUILD_ID_EVENT_KEY);
|
|
38
|
+
|
|
39
|
+
// Location Event
|
|
40
|
+
const LOCATION_EVENT_KEY = "vorma:location";
|
|
41
|
+
export function dispatchLocationEvent(): void {
|
|
42
|
+
window.dispatchEvent(new CustomEvent(LOCATION_EVENT_KEY));
|
|
43
|
+
}
|
|
44
|
+
export const addLocationListener = makeListenerAdder<void>(LOCATION_EVENT_KEY);
|
|
45
|
+
|
|
46
|
+
// Helper to create listener adders
|
|
47
|
+
function makeListenerAdder<T>(key: string) {
|
|
48
|
+
return function addListener(
|
|
49
|
+
listener: (event: CustomEvent<T>) => void,
|
|
50
|
+
): () => void {
|
|
51
|
+
window.addEventListener(key, listener as any);
|
|
52
|
+
return () => window.removeEventListener(key, listener as any);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { getStatus } from "../client.ts";
|
|
2
|
+
import { addStatusListener, type StatusEvent } from "../events.ts";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_DELAY = 12;
|
|
5
|
+
|
|
6
|
+
type GlobalLoadingIndicatorIncludesOption =
|
|
7
|
+
| "navigations"
|
|
8
|
+
| "submissions"
|
|
9
|
+
| "revalidations";
|
|
10
|
+
|
|
11
|
+
type GlobalLoadingIndicatorConfig = {
|
|
12
|
+
start: () => void;
|
|
13
|
+
stop: () => void;
|
|
14
|
+
isRunning: () => boolean;
|
|
15
|
+
include?: "all" | Array<GlobalLoadingIndicatorIncludesOption>;
|
|
16
|
+
startDelayMS?: number;
|
|
17
|
+
stopDelayMS?: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type ParsedGlobalLoadingIndicatorConfig = {
|
|
21
|
+
includesAll: boolean;
|
|
22
|
+
includesNavigations: boolean;
|
|
23
|
+
includesSubmissions: boolean;
|
|
24
|
+
includesRevalidations: boolean;
|
|
25
|
+
startDelayMS: number;
|
|
26
|
+
stopDelayMS: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function resolveIncludes(
|
|
30
|
+
config: GlobalLoadingIndicatorConfig,
|
|
31
|
+
includesOption: GlobalLoadingIndicatorIncludesOption,
|
|
32
|
+
) {
|
|
33
|
+
const isArray = Array.isArray(config.include);
|
|
34
|
+
return isArray && config.include?.includes(includesOption);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function setupGlobalLoadingIndicator(
|
|
38
|
+
config: GlobalLoadingIndicatorConfig,
|
|
39
|
+
) {
|
|
40
|
+
let gliDebounceStartTimer: number | null = null;
|
|
41
|
+
let gliDebounceStopTimer: number | null = null;
|
|
42
|
+
const includesAll = !config.include || config.include === "all";
|
|
43
|
+
const pc: ParsedGlobalLoadingIndicatorConfig = {
|
|
44
|
+
includesAll,
|
|
45
|
+
includesNavigations:
|
|
46
|
+
resolveIncludes(config, "navigations") || includesAll,
|
|
47
|
+
includesSubmissions:
|
|
48
|
+
resolveIncludes(config, "submissions") || includesAll,
|
|
49
|
+
includesRevalidations:
|
|
50
|
+
resolveIncludes(config, "revalidations") || includesAll,
|
|
51
|
+
startDelayMS: config.startDelayMS ?? DEFAULT_DELAY,
|
|
52
|
+
stopDelayMS: config.stopDelayMS ?? DEFAULT_DELAY,
|
|
53
|
+
};
|
|
54
|
+
function clearStartTimer() {
|
|
55
|
+
if (gliDebounceStartTimer) {
|
|
56
|
+
window.clearTimeout(gliDebounceStartTimer);
|
|
57
|
+
gliDebounceStartTimer = null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function clearStopTimer() {
|
|
61
|
+
if (gliDebounceStopTimer) {
|
|
62
|
+
window.clearTimeout(gliDebounceStopTimer);
|
|
63
|
+
gliDebounceStopTimer = null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function clearTimers() {
|
|
67
|
+
clearStartTimer();
|
|
68
|
+
clearStopTimer();
|
|
69
|
+
}
|
|
70
|
+
function handleStatusChange(e?: StatusEvent) {
|
|
71
|
+
const shouldBeWorking = getIsWorking(pc, e);
|
|
72
|
+
if (shouldBeWorking) {
|
|
73
|
+
clearStopTimer();
|
|
74
|
+
if (!gliDebounceStartTimer) {
|
|
75
|
+
gliDebounceStartTimer = window.setTimeout(() => {
|
|
76
|
+
gliDebounceStartTimer = null;
|
|
77
|
+
if (!config.isRunning() && getIsWorking(pc)) {
|
|
78
|
+
config.start();
|
|
79
|
+
}
|
|
80
|
+
}, pc.startDelayMS);
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
clearStartTimer();
|
|
84
|
+
if (!gliDebounceStopTimer) {
|
|
85
|
+
gliDebounceStopTimer = window.setTimeout(() => {
|
|
86
|
+
gliDebounceStopTimer = null;
|
|
87
|
+
if (config.isRunning() && !getIsWorking(pc)) {
|
|
88
|
+
config.stop();
|
|
89
|
+
}
|
|
90
|
+
}, pc.stopDelayMS);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
handleStatusChange();
|
|
95
|
+
const removeStatusListenerCallback = addStatusListener(handleStatusChange);
|
|
96
|
+
return () => {
|
|
97
|
+
removeStatusListenerCallback();
|
|
98
|
+
clearTimers();
|
|
99
|
+
if (config.isRunning()) {
|
|
100
|
+
config.stop();
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function getIsWorking(
|
|
106
|
+
pc: ParsedGlobalLoadingIndicatorConfig,
|
|
107
|
+
e?: StatusEvent,
|
|
108
|
+
): boolean {
|
|
109
|
+
const status = e?.detail ?? getStatus();
|
|
110
|
+
if (pc.includesAll) {
|
|
111
|
+
return (
|
|
112
|
+
status.isNavigating || status.isSubmitting || status.isRevalidating
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (pc.includesNavigations && status.isNavigating) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
if (pc.includesSubmissions && status.isSubmitting) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
if (pc.includesRevalidations && status.isRevalidating) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const VORMA_HARD_RELOAD_QUERY_PARAM = "vorma_reload";
|