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.
Files changed (225) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +48 -0
  3. package/internal/framework/_typescript/client/index.ts +64 -0
  4. package/internal/framework/_typescript/client/src/asset_manager.ts +67 -0
  5. package/internal/framework/_typescript/client/src/client.ts +1201 -0
  6. package/internal/framework/_typescript/client/src/client_loaders.ts +249 -0
  7. package/internal/framework/_typescript/client/src/component_loader.ts +105 -0
  8. package/internal/framework/_typescript/client/src/error_boundary.ts +7 -0
  9. package/internal/framework/_typescript/client/src/events.ts +54 -0
  10. package/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.ts +125 -0
  11. package/internal/framework/_typescript/client/src/hard_reload.ts +1 -0
  12. package/internal/framework/_typescript/client/src/head_elements/head_elements.ts +193 -0
  13. package/internal/framework/_typescript/client/src/history/history.ts +118 -0
  14. package/internal/framework/_typescript/client/src/history/npm_history_types.ts +83 -0
  15. package/internal/framework/_typescript/client/src/hmr/hmr.ts +71 -0
  16. package/internal/framework/_typescript/client/src/init_client.ts +134 -0
  17. package/internal/framework/_typescript/client/src/links.ts +218 -0
  18. package/internal/framework/_typescript/client/src/redirects/redirects.ts +203 -0
  19. package/internal/framework/_typescript/client/src/rendering.ts +135 -0
  20. package/internal/framework/_typescript/client/src/resolve_public_href.ts +15 -0
  21. package/internal/framework/_typescript/client/src/scroll_state_manager.ts +100 -0
  22. package/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.ts +22 -0
  23. package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.ts +131 -0
  24. package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.ts +56 -0
  25. package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.ts +58 -0
  26. package/internal/framework/_typescript/client/src/utils/errors.ts +10 -0
  27. package/internal/framework/_typescript/client/src/utils/logging.ts +7 -0
  28. package/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.ts +290 -0
  29. package/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.ts +128 -0
  30. package/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.ts +32 -0
  31. package/internal/framework/_typescript/client/tsconfig.json +3 -0
  32. package/internal/framework/_typescript/create/main.ts +378 -0
  33. package/internal/framework/_typescript/create/package.json +33 -0
  34. package/internal/framework/_typescript/create/pnpm-lock.yaml +70 -0
  35. package/internal/framework/_typescript/create/tsconfig.json +3 -0
  36. package/internal/framework/_typescript/preact/index.tsx +10 -0
  37. package/internal/framework/_typescript/preact/src/helpers.ts +113 -0
  38. package/internal/framework/_typescript/preact/src/link.tsx +107 -0
  39. package/internal/framework/_typescript/preact/src/preact.tsx +191 -0
  40. package/internal/framework/_typescript/preact/tsconfig.json +7 -0
  41. package/internal/framework/_typescript/react/index.tsx +10 -0
  42. package/internal/framework/_typescript/react/src/helpers.ts +118 -0
  43. package/internal/framework/_typescript/react/src/link.tsx +115 -0
  44. package/internal/framework/_typescript/react/src/react.tsx +299 -0
  45. package/internal/framework/_typescript/react/tsconfig.json +6 -0
  46. package/internal/framework/_typescript/solid/index.tsx +10 -0
  47. package/internal/framework/_typescript/solid/src/helpers.ts +114 -0
  48. package/internal/framework/_typescript/solid/src/link.tsx +104 -0
  49. package/internal/framework/_typescript/solid/src/solid.tsx +204 -0
  50. package/internal/framework/_typescript/solid/tsconfig.json +7 -0
  51. package/internal/framework/_typescript/vite/tsconfig.json +3 -0
  52. package/internal/framework/_typescript/vite/vite.ts +93 -0
  53. package/internal/site/frontend/assets/vorma-banner.webp +0 -0
  54. package/kit/_typescript/converters/converters.ts +152 -0
  55. package/kit/_typescript/cookies/cookies.ts +18 -0
  56. package/kit/_typescript/csrf/csrf.ts +10 -0
  57. package/kit/_typescript/debounce/debounce.ts +17 -0
  58. package/kit/_typescript/fmt/fmt.ts +3 -0
  59. package/kit/_typescript/json/deep_equals.ts +54 -0
  60. package/kit/_typescript/json/json.ts +3 -0
  61. package/kit/_typescript/json/search_param_serializer.ts +49 -0
  62. package/kit/_typescript/json/stringify_stable.ts +43 -0
  63. package/kit/_typescript/listeners/listeners.ts +16 -0
  64. package/kit/_typescript/matcher/find_best_match.ts +205 -0
  65. package/kit/_typescript/matcher/find_nested_matches.ts +357 -0
  66. package/kit/_typescript/matcher/parse_segments.ts +30 -0
  67. package/kit/_typescript/matcher/register.ts +271 -0
  68. package/kit/_typescript/theme/theme.ts +177 -0
  69. package/kit/_typescript/tsconfig.json +3 -0
  70. package/kit/_typescript/url/url.ts +132 -0
  71. package/npm_dist/internal/framework/_typescript/client/index.d.ts +17 -0
  72. package/npm_dist/internal/framework/_typescript/client/index.d.ts.map +1 -0
  73. package/npm_dist/internal/framework/_typescript/client/index.js +2489 -0
  74. package/npm_dist/internal/framework/_typescript/client/index.js.map +7 -0
  75. package/npm_dist/internal/framework/_typescript/client/src/asset_manager.d.ts +6 -0
  76. package/npm_dist/internal/framework/_typescript/client/src/asset_manager.d.ts.map +1 -0
  77. package/npm_dist/internal/framework/_typescript/client/src/client.d.ts +119 -0
  78. package/npm_dist/internal/framework/_typescript/client/src/client.d.ts.map +1 -0
  79. package/npm_dist/internal/framework/_typescript/client/src/client_loaders.d.ts +18 -0
  80. package/npm_dist/internal/framework/_typescript/client/src/client_loaders.d.ts.map +1 -0
  81. package/npm_dist/internal/framework/_typescript/client/src/component_loader.d.ts +10 -0
  82. package/npm_dist/internal/framework/_typescript/client/src/component_loader.d.ts.map +1 -0
  83. package/npm_dist/internal/framework/_typescript/client/src/error_boundary.d.ts +3 -0
  84. package/npm_dist/internal/framework/_typescript/client/src/error_boundary.d.ts.map +1 -0
  85. package/npm_dist/internal/framework/_typescript/client/src/events.d.ts +26 -0
  86. package/npm_dist/internal/framework/_typescript/client/src/events.d.ts.map +1 -0
  87. package/npm_dist/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.d.ts +12 -0
  88. package/npm_dist/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.d.ts.map +1 -0
  89. package/npm_dist/internal/framework/_typescript/client/src/hard_reload.d.ts +2 -0
  90. package/npm_dist/internal/framework/_typescript/client/src/hard_reload.d.ts.map +1 -0
  91. package/npm_dist/internal/framework/_typescript/client/src/head_elements/head_elements.d.ts +7 -0
  92. package/npm_dist/internal/framework/_typescript/client/src/head_elements/head_elements.d.ts.map +1 -0
  93. package/npm_dist/internal/framework/_typescript/client/src/history/history.d.ts +14 -0
  94. package/npm_dist/internal/framework/_typescript/client/src/history/history.d.ts.map +1 -0
  95. package/npm_dist/internal/framework/_typescript/client/src/history/npm_history_types.d.ts +84 -0
  96. package/npm_dist/internal/framework/_typescript/client/src/history/npm_history_types.d.ts.map +1 -0
  97. package/npm_dist/internal/framework/_typescript/client/src/hmr/hmr.d.ts +3 -0
  98. package/npm_dist/internal/framework/_typescript/client/src/hmr/hmr.d.ts.map +1 -0
  99. package/npm_dist/internal/framework/_typescript/client/src/init_client.d.ts +9 -0
  100. package/npm_dist/internal/framework/_typescript/client/src/init_client.d.ts.map +1 -0
  101. package/npm_dist/internal/framework/_typescript/client/src/links.d.ts +33 -0
  102. package/npm_dist/internal/framework/_typescript/client/src/links.d.ts.map +1 -0
  103. package/npm_dist/internal/framework/_typescript/client/src/redirects/redirects.d.ts +26 -0
  104. package/npm_dist/internal/framework/_typescript/client/src/redirects/redirects.d.ts.map +1 -0
  105. package/npm_dist/internal/framework/_typescript/client/src/rendering.d.ts +18 -0
  106. package/npm_dist/internal/framework/_typescript/client/src/rendering.d.ts.map +1 -0
  107. package/npm_dist/internal/framework/_typescript/client/src/resolve_public_href.d.ts +2 -0
  108. package/npm_dist/internal/framework/_typescript/client/src/resolve_public_href.d.ts.map +1 -0
  109. package/npm_dist/internal/framework/_typescript/client/src/scroll_state_manager.d.ts +22 -0
  110. package/npm_dist/internal/framework/_typescript/client/src/scroll_state_manager.d.ts.map +1 -0
  111. package/npm_dist/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.d.ts +12 -0
  112. package/npm_dist/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.d.ts.map +1 -0
  113. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.d.ts +28 -0
  114. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.d.ts.map +1 -0
  115. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.d.ts +18 -0
  116. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.d.ts.map +1 -0
  117. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.d.ts +11 -0
  118. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.d.ts.map +1 -0
  119. package/npm_dist/internal/framework/_typescript/client/src/utils/errors.d.ts +3 -0
  120. package/npm_dist/internal/framework/_typescript/client/src/utils/errors.d.ts.map +1 -0
  121. package/npm_dist/internal/framework/_typescript/client/src/utils/logging.d.ts +3 -0
  122. package/npm_dist/internal/framework/_typescript/client/src/utils/logging.d.ts.map +1 -0
  123. package/npm_dist/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.d.ts +119 -0
  124. package/npm_dist/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.d.ts.map +1 -0
  125. package/npm_dist/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.d.ts +88 -0
  126. package/npm_dist/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.d.ts.map +1 -0
  127. package/npm_dist/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.d.ts +10 -0
  128. package/npm_dist/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.d.ts.map +1 -0
  129. package/npm_dist/internal/framework/_typescript/create/main.d.ts +3 -0
  130. package/npm_dist/internal/framework/_typescript/create/main.d.ts.map +1 -0
  131. package/npm_dist/internal/framework/_typescript/preact/index.d.ts +4 -0
  132. package/npm_dist/internal/framework/_typescript/preact/index.d.ts.map +1 -0
  133. package/npm_dist/internal/framework/_typescript/preact/index.js +283 -0
  134. package/npm_dist/internal/framework/_typescript/preact/index.js.map +7 -0
  135. package/npm_dist/internal/framework/_typescript/preact/src/helpers.d.ts +21 -0
  136. package/npm_dist/internal/framework/_typescript/preact/src/helpers.d.ts.map +1 -0
  137. package/npm_dist/internal/framework/_typescript/preact/src/link.d.ts +11 -0
  138. package/npm_dist/internal/framework/_typescript/preact/src/link.d.ts.map +1 -0
  139. package/npm_dist/internal/framework/_typescript/preact/src/preact.d.ts +21 -0
  140. package/npm_dist/internal/framework/_typescript/preact/src/preact.d.ts.map +1 -0
  141. package/npm_dist/internal/framework/_typescript/react/index.d.ts +4 -0
  142. package/npm_dist/internal/framework/_typescript/react/index.d.ts.map +1 -0
  143. package/npm_dist/internal/framework/_typescript/react/index.js +370 -0
  144. package/npm_dist/internal/framework/_typescript/react/index.js.map +7 -0
  145. package/npm_dist/internal/framework/_typescript/react/src/helpers.d.ts +21 -0
  146. package/npm_dist/internal/framework/_typescript/react/src/helpers.d.ts.map +1 -0
  147. package/npm_dist/internal/framework/_typescript/react/src/link.d.ts +11 -0
  148. package/npm_dist/internal/framework/_typescript/react/src/link.d.ts.map +1 -0
  149. package/npm_dist/internal/framework/_typescript/react/src/react.d.ts +20 -0
  150. package/npm_dist/internal/framework/_typescript/react/src/react.d.ts.map +1 -0
  151. package/npm_dist/internal/framework/_typescript/solid/index.d.ts +4 -0
  152. package/npm_dist/internal/framework/_typescript/solid/index.d.ts.map +1 -0
  153. package/npm_dist/internal/framework/_typescript/solid/index.js +314 -0
  154. package/npm_dist/internal/framework/_typescript/solid/index.js.map +7 -0
  155. package/npm_dist/internal/framework/_typescript/solid/src/helpers.d.ts +22 -0
  156. package/npm_dist/internal/framework/_typescript/solid/src/helpers.d.ts.map +1 -0
  157. package/npm_dist/internal/framework/_typescript/solid/src/link.d.ts +11 -0
  158. package/npm_dist/internal/framework/_typescript/solid/src/link.d.ts.map +1 -0
  159. package/npm_dist/internal/framework/_typescript/solid/src/solid.d.ts +22 -0
  160. package/npm_dist/internal/framework/_typescript/solid/src/solid.d.ts.map +1 -0
  161. package/npm_dist/internal/framework/_typescript/vite/vite.d.ts +11 -0
  162. package/npm_dist/internal/framework/_typescript/vite/vite.d.ts.map +1 -0
  163. package/npm_dist/internal/framework/_typescript/vite/vite.js +82 -0
  164. package/npm_dist/internal/framework/_typescript/vite/vite.js.map +7 -0
  165. package/npm_dist/kit/_typescript/chunk-YBAPNBS2.js +202 -0
  166. package/npm_dist/kit/_typescript/chunk-YBAPNBS2.js.map +7 -0
  167. package/npm_dist/kit/_typescript/converters/converters.d.ts +26 -0
  168. package/npm_dist/kit/_typescript/converters/converters.d.ts.map +1 -0
  169. package/npm_dist/kit/_typescript/converters/converters.js +99 -0
  170. package/npm_dist/kit/_typescript/converters/converters.js.map +7 -0
  171. package/npm_dist/kit/_typescript/cookies/cookies.d.ts +13 -0
  172. package/npm_dist/kit/_typescript/cookies/cookies.d.ts.map +1 -0
  173. package/npm_dist/kit/_typescript/cookies/cookies.js +13 -0
  174. package/npm_dist/kit/_typescript/cookies/cookies.js.map +7 -0
  175. package/npm_dist/kit/_typescript/csrf/csrf.d.ts +5 -0
  176. package/npm_dist/kit/_typescript/csrf/csrf.d.ts.map +1 -0
  177. package/npm_dist/kit/_typescript/csrf/csrf.js +11 -0
  178. package/npm_dist/kit/_typescript/csrf/csrf.js.map +7 -0
  179. package/npm_dist/kit/_typescript/debounce/debounce.d.ts +4 -0
  180. package/npm_dist/kit/_typescript/debounce/debounce.d.ts.map +1 -0
  181. package/npm_dist/kit/_typescript/debounce/debounce.js +16 -0
  182. package/npm_dist/kit/_typescript/debounce/debounce.js.map +7 -0
  183. package/npm_dist/kit/_typescript/fmt/fmt.d.ts +2 -0
  184. package/npm_dist/kit/_typescript/fmt/fmt.d.ts.map +1 -0
  185. package/npm_dist/kit/_typescript/fmt/fmt.js +8 -0
  186. package/npm_dist/kit/_typescript/fmt/fmt.js.map +7 -0
  187. package/npm_dist/kit/_typescript/json/deep_equals.d.ts +7 -0
  188. package/npm_dist/kit/_typescript/json/deep_equals.d.ts.map +1 -0
  189. package/npm_dist/kit/_typescript/json/json.d.ts +4 -0
  190. package/npm_dist/kit/_typescript/json/json.d.ts.map +1 -0
  191. package/npm_dist/kit/_typescript/json/json.js +110 -0
  192. package/npm_dist/kit/_typescript/json/json.js.map +7 -0
  193. package/npm_dist/kit/_typescript/json/search_param_serializer.d.ts +2 -0
  194. package/npm_dist/kit/_typescript/json/search_param_serializer.d.ts.map +1 -0
  195. package/npm_dist/kit/_typescript/json/stringify_stable.d.ts +7 -0
  196. package/npm_dist/kit/_typescript/json/stringify_stable.d.ts.map +1 -0
  197. package/npm_dist/kit/_typescript/listeners/listeners.d.ts +2 -0
  198. package/npm_dist/kit/_typescript/listeners/listeners.d.ts.map +1 -0
  199. package/npm_dist/kit/_typescript/listeners/listeners.js +20 -0
  200. package/npm_dist/kit/_typescript/listeners/listeners.js.map +7 -0
  201. package/npm_dist/kit/_typescript/matcher/find_best_match.d.ts +10 -0
  202. package/npm_dist/kit/_typescript/matcher/find_best_match.d.ts.map +1 -0
  203. package/npm_dist/kit/_typescript/matcher/find_best_match.js +146 -0
  204. package/npm_dist/kit/_typescript/matcher/find_best_match.js.map +7 -0
  205. package/npm_dist/kit/_typescript/matcher/find_nested_matches.d.ts +14 -0
  206. package/npm_dist/kit/_typescript/matcher/find_nested_matches.d.ts.map +1 -0
  207. package/npm_dist/kit/_typescript/matcher/find_nested_matches.js +248 -0
  208. package/npm_dist/kit/_typescript/matcher/find_nested_matches.js.map +7 -0
  209. package/npm_dist/kit/_typescript/matcher/parse_segments.d.ts +2 -0
  210. package/npm_dist/kit/_typescript/matcher/parse_segments.d.ts.map +1 -0
  211. package/npm_dist/kit/_typescript/matcher/register.d.ts +54 -0
  212. package/npm_dist/kit/_typescript/matcher/register.d.ts.map +1 -0
  213. package/npm_dist/kit/_typescript/matcher/register.js +21 -0
  214. package/npm_dist/kit/_typescript/matcher/register.js.map +7 -0
  215. package/npm_dist/kit/_typescript/theme/theme.d.ts +24 -0
  216. package/npm_dist/kit/_typescript/theme/theme.d.ts.map +1 -0
  217. package/npm_dist/kit/_typescript/theme/theme.js +133 -0
  218. package/npm_dist/kit/_typescript/theme/theme.js.map +7 -0
  219. package/npm_dist/kit/_typescript/url/url.d.ts +30 -0
  220. package/npm_dist/kit/_typescript/url/url.d.ts.map +1 -0
  221. package/npm_dist/kit/_typescript/url/url.js +100 -0
  222. package/npm_dist/kit/_typescript/url/url.js.map +7 -0
  223. package/package.json +135 -3
  224. package/tsconfig.base.json +17 -0
  225. 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,7 @@
1
+ import type { RouteErrorComponent } from "./vorma_ctx/vorma_ctx.ts";
2
+
3
+ export const defaultErrorBoundary: RouteErrorComponent = (props: {
4
+ error: string;
5
+ }) => {
6
+ return "Route Error: " + props.error;
7
+ };
@@ -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";