vorma 0.0.0-pre.0 → 0.82.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 +166 -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 +23 -0
- package/npm_dist/kit/_typescript/theme/theme.d.ts.map +1 -0
- package/npm_dist/kit/_typescript/theme/theme.js +122 -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,204 @@
|
|
|
1
|
+
import {
|
|
2
|
+
batch,
|
|
3
|
+
createEffect,
|
|
4
|
+
createMemo,
|
|
5
|
+
createRenderEffect,
|
|
6
|
+
createSignal,
|
|
7
|
+
type JSX,
|
|
8
|
+
Show,
|
|
9
|
+
} from "solid-js";
|
|
10
|
+
import { Dynamic } from "solid-js/web";
|
|
11
|
+
import {
|
|
12
|
+
__applyScrollState,
|
|
13
|
+
addLocationListener,
|
|
14
|
+
addRouteChangeListener,
|
|
15
|
+
__vormaClientGlobal as ctx,
|
|
16
|
+
getLocation,
|
|
17
|
+
getRouterData,
|
|
18
|
+
type RouteChangeEvent,
|
|
19
|
+
} from "vorma/client";
|
|
20
|
+
|
|
21
|
+
/////////////////////////////////////////////////////////////////////
|
|
22
|
+
/////// CORE SETUP
|
|
23
|
+
/////////////////////////////////////////////////////////////////////
|
|
24
|
+
|
|
25
|
+
const [latestEvent, setLatestEvent] = createSignal<RouteChangeEvent | null>(
|
|
26
|
+
null,
|
|
27
|
+
);
|
|
28
|
+
const [loadersData, setLoadersData] = createSignal(ctx.get("loadersData"));
|
|
29
|
+
const [clientLoadersData, setClientLoadersData] = createSignal(
|
|
30
|
+
ctx.get("clientLoadersData"),
|
|
31
|
+
);
|
|
32
|
+
const [routerData, setRouterData] = createSignal(getRouterData());
|
|
33
|
+
const [outermostErrorIdx, setOutermostErrorIdx] = createSignal(
|
|
34
|
+
ctx.get("outermostErrorIdx"),
|
|
35
|
+
);
|
|
36
|
+
const [outermostError, setOutermostError] = createSignal(
|
|
37
|
+
ctx.get("outermostError"),
|
|
38
|
+
);
|
|
39
|
+
const [activeComponents, setActiveComponents] = createSignal(
|
|
40
|
+
ctx.get("activeComponents"),
|
|
41
|
+
);
|
|
42
|
+
const [activeErrorBoundary, setActiveErrorBoundary] = createSignal(
|
|
43
|
+
ctx.get("activeErrorBoundary"),
|
|
44
|
+
);
|
|
45
|
+
const [importURLs, setImportURLs] = createSignal(ctx.get("importURLs"));
|
|
46
|
+
const [exportKeys, setExportKeys] = createSignal(ctx.get("exportKeys"));
|
|
47
|
+
|
|
48
|
+
export { clientLoadersData, loadersData, routerData };
|
|
49
|
+
|
|
50
|
+
let isInited = false;
|
|
51
|
+
|
|
52
|
+
function initUIListeners() {
|
|
53
|
+
if (isInited) return;
|
|
54
|
+
isInited = true;
|
|
55
|
+
|
|
56
|
+
addRouteChangeListener((e) => {
|
|
57
|
+
batch(() => {
|
|
58
|
+
setLatestEvent(e);
|
|
59
|
+
setLoadersData(ctx.get("loadersData"));
|
|
60
|
+
setClientLoadersData(ctx.get("clientLoadersData"));
|
|
61
|
+
setRouterData(getRouterData());
|
|
62
|
+
setOutermostErrorIdx(ctx.get("outermostErrorIdx"));
|
|
63
|
+
setOutermostError(ctx.get("outermostError"));
|
|
64
|
+
setActiveComponents(ctx.get("activeComponents"));
|
|
65
|
+
setActiveErrorBoundary(ctx.get("activeErrorBoundary"));
|
|
66
|
+
setImportURLs(ctx.get("importURLs"));
|
|
67
|
+
setExportKeys(ctx.get("exportKeys"));
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
addLocationListener(() => {
|
|
72
|
+
setLocation(getLocation());
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const [location, setLocation] = createSignal(getLocation());
|
|
77
|
+
|
|
78
|
+
export { location };
|
|
79
|
+
|
|
80
|
+
/////////////////////////////////////////////////////////////////////
|
|
81
|
+
/////// COMPONENT
|
|
82
|
+
/////////////////////////////////////////////////////////////////////
|
|
83
|
+
|
|
84
|
+
export function VormaRootOutlet(props: { idx?: number }): JSX.Element {
|
|
85
|
+
const idx = props.idx ?? 0;
|
|
86
|
+
|
|
87
|
+
if (idx === 0) {
|
|
88
|
+
initUIListeners();
|
|
89
|
+
|
|
90
|
+
batch(() => {
|
|
91
|
+
setLoadersData(ctx.get("loadersData"));
|
|
92
|
+
setClientLoadersData(ctx.get("clientLoadersData"));
|
|
93
|
+
setRouterData(getRouterData());
|
|
94
|
+
setOutermostErrorIdx(ctx.get("outermostErrorIdx"));
|
|
95
|
+
setOutermostError(ctx.get("outermostError"));
|
|
96
|
+
setActiveComponents(ctx.get("activeComponents"));
|
|
97
|
+
setActiveErrorBoundary(ctx.get("activeErrorBoundary"));
|
|
98
|
+
setImportURLs(ctx.get("importURLs"));
|
|
99
|
+
setExportKeys(ctx.get("exportKeys"));
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const [currentImportURL, setCurrentImportURL] = createSignal(
|
|
104
|
+
importURLs()?.[idx],
|
|
105
|
+
);
|
|
106
|
+
const [currentExportKey, setCurrentExportKey] = createSignal(
|
|
107
|
+
exportKeys()?.[idx],
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
createEffect(() => {
|
|
111
|
+
if (!currentImportURL()) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const e = latestEvent();
|
|
115
|
+
if (!e) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const newCurrentImportURL = importURLs()?.[idx];
|
|
120
|
+
const newCurrentExportKey = exportKeys()?.[idx];
|
|
121
|
+
|
|
122
|
+
if (currentImportURL() !== newCurrentImportURL) {
|
|
123
|
+
setCurrentImportURL(newCurrentImportURL);
|
|
124
|
+
}
|
|
125
|
+
if (currentExportKey() !== newCurrentExportKey) {
|
|
126
|
+
setCurrentExportKey(newCurrentExportKey);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
createRenderEffect(() => {
|
|
131
|
+
const e = latestEvent();
|
|
132
|
+
if (!e || idx !== 0) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
window.requestAnimationFrame(() => {
|
|
136
|
+
__applyScrollState(e.detail.__scrollState);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const isErrorIdxMemo = createMemo(() => {
|
|
141
|
+
return idx === outermostErrorIdx();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const currentCompMemo = createMemo(() => {
|
|
145
|
+
if (isErrorIdxMemo()) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
currentImportURL();
|
|
149
|
+
currentExportKey();
|
|
150
|
+
return activeComponents()?.[idx];
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const shouldFallbackOutletMemo = createMemo(() => {
|
|
154
|
+
if (isErrorIdxMemo() || currentCompMemo()) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return idx + 1 < loadersData().length;
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const errorCompMemo = createMemo(() => {
|
|
161
|
+
if (!isErrorIdxMemo()) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return activeErrorBoundary();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const remountKeyNext = createMemo(
|
|
168
|
+
() => `${importURLs()[idx + 1]}|${exportKeys()[idx + 1]}`,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const Outlet = (localProps: Record<string, any> | undefined) => (
|
|
172
|
+
<Show when={remountKeyNext()} keyed>
|
|
173
|
+
<VormaRootOutlet {...localProps} {...props} idx={idx + 1} />
|
|
174
|
+
</Show>
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<>
|
|
179
|
+
<Show when={currentCompMemo()}>
|
|
180
|
+
<Dynamic
|
|
181
|
+
component={currentCompMemo()}
|
|
182
|
+
idx={idx}
|
|
183
|
+
Outlet={Outlet}
|
|
184
|
+
/>
|
|
185
|
+
</Show>
|
|
186
|
+
|
|
187
|
+
<Show when={shouldFallbackOutletMemo()}>
|
|
188
|
+
<Outlet />
|
|
189
|
+
</Show>
|
|
190
|
+
|
|
191
|
+
<Show when={isErrorIdxMemo()}>
|
|
192
|
+
<Show
|
|
193
|
+
when={errorCompMemo()}
|
|
194
|
+
fallback={`Error: ${outermostError() || "unknown"}`}
|
|
195
|
+
>
|
|
196
|
+
<Dynamic
|
|
197
|
+
component={errorCompMemo()}
|
|
198
|
+
error={outermostError()}
|
|
199
|
+
/>
|
|
200
|
+
</Show>
|
|
201
|
+
</Show>
|
|
202
|
+
</>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
type VormaVitePluginConfig = {
|
|
2
|
+
rollupInput: ReadonlyArray<string>;
|
|
3
|
+
publicPathPrefix: string;
|
|
4
|
+
staticPublicAssetMap: Record<string, string>;
|
|
5
|
+
buildtimePublicURLFuncName: string;
|
|
6
|
+
ignoredPatterns: ReadonlyArray<string>;
|
|
7
|
+
dedupeList: ReadonlyArray<string>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function vormaVitePlugin(config: VormaVitePluginConfig): any {
|
|
11
|
+
return {
|
|
12
|
+
name: "vorma-vite-plugin",
|
|
13
|
+
config(c: any, { command }: any) {
|
|
14
|
+
const mp = c.build?.modulePreload;
|
|
15
|
+
const roi = c.build?.rollupOptions?.input;
|
|
16
|
+
const ign = c.server?.watch?.ignored;
|
|
17
|
+
const dedupe = c.resolve?.dedupe;
|
|
18
|
+
|
|
19
|
+
const isDev = command === "serve";
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
base: isDev ? "/" : config.publicPathPrefix,
|
|
23
|
+
build: {
|
|
24
|
+
target: "es2022",
|
|
25
|
+
emptyOutDir: false,
|
|
26
|
+
modulePreload: {
|
|
27
|
+
polyfill: false,
|
|
28
|
+
...(typeof mp === "object" ? mp : {}),
|
|
29
|
+
},
|
|
30
|
+
rollupOptions: {
|
|
31
|
+
...c.build?.rollupOptions,
|
|
32
|
+
input: [
|
|
33
|
+
...config.rollupInput,
|
|
34
|
+
...(Array.isArray(roi) ? roi : []),
|
|
35
|
+
],
|
|
36
|
+
preserveEntrySignatures: "exports-only",
|
|
37
|
+
output: {
|
|
38
|
+
assetFileNames:
|
|
39
|
+
"vorma_out_vite_[name]-[hash][extname]",
|
|
40
|
+
chunkFileNames: "vorma_out_vite_[name]-[hash].js",
|
|
41
|
+
entryFileNames: "vorma_out_vite_[name]-[hash].js",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
server: {
|
|
46
|
+
headers: {
|
|
47
|
+
...c.server?.headers,
|
|
48
|
+
// ensure versions of dynamic imports without the latest
|
|
49
|
+
// hmr updates are not cached by the browser during dev
|
|
50
|
+
"cache-control": "no-store",
|
|
51
|
+
},
|
|
52
|
+
watch: {
|
|
53
|
+
...c.server?.watch,
|
|
54
|
+
ignored: [
|
|
55
|
+
...(Array.isArray(ign) ? ign : []),
|
|
56
|
+
...config.ignoredPatterns,
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
resolve: {
|
|
61
|
+
dedupe: [
|
|
62
|
+
...(Array.isArray(dedupe) ? dedupe : []),
|
|
63
|
+
...config.dedupeList,
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
transform(code: any, id: any) {
|
|
69
|
+
const isNodeModules = /node_modules/.test(id);
|
|
70
|
+
if (isNodeModules) return null;
|
|
71
|
+
|
|
72
|
+
const regex = new RegExp(
|
|
73
|
+
`${config.buildtimePublicURLFuncName}\\s*\\(\\s*(["'\`])(.*?)\\1\\s*\\)`,
|
|
74
|
+
"g",
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const needsReplacement = regex.test(code);
|
|
78
|
+
if (!needsReplacement) return null;
|
|
79
|
+
|
|
80
|
+
const replacedCode = code.replace(
|
|
81
|
+
regex,
|
|
82
|
+
(_: any, __: any, assetPath: any) => {
|
|
83
|
+
const hashed = config.staticPublicAssetMap[assetPath];
|
|
84
|
+
if (!hashed) return `"${assetPath}"`;
|
|
85
|
+
return `"${config.publicPathPrefix}${hashed}"`;
|
|
86
|
+
},
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (replacedCode === code) return null;
|
|
90
|
+
return replacedCode;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/////////////////////////////////////////////////////////////////////
|
|
2
|
+
/////// TYPE ALIASES
|
|
3
|
+
/////////////////////////////////////////////////////////////////////
|
|
4
|
+
|
|
5
|
+
export type Bytes = Uint8Array;
|
|
6
|
+
export type UTF8 = string;
|
|
7
|
+
export type Hex = string;
|
|
8
|
+
export type Base64 = string;
|
|
9
|
+
export type Base64URL = string;
|
|
10
|
+
|
|
11
|
+
/////////////////////////////////////////////////////////////////////
|
|
12
|
+
/////// BYTES --> X
|
|
13
|
+
/////////////////////////////////////////////////////////////////////
|
|
14
|
+
|
|
15
|
+
// --> UTF8
|
|
16
|
+
export function bytesToUTF8(bytes: Uint8Array): UTF8 {
|
|
17
|
+
return new TextDecoder().decode(bytes);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// --> HEX
|
|
21
|
+
export function bytesToHex(bytes: Uint8Array): Hex {
|
|
22
|
+
return Array.from(bytes, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// --> BASE64
|
|
26
|
+
export function bytesToBase64(bytes: Uint8Array): Base64 {
|
|
27
|
+
const callback = (x: number) => String.fromCodePoint(x);
|
|
28
|
+
return btoa(Array.from(bytes, callback).join(""));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// --> BASE64URL
|
|
32
|
+
export function bytesToBase64URL(bytes: Uint8Array): Base64 {
|
|
33
|
+
const base64 = bytesToBase64(bytes);
|
|
34
|
+
return base64ToBase64URL(base64);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/////////////////////////////////////////////////////////////////////
|
|
38
|
+
/////// UTF8 --> X
|
|
39
|
+
/////////////////////////////////////////////////////////////////////
|
|
40
|
+
|
|
41
|
+
// --> BYTES
|
|
42
|
+
export function utf8ToBytes(utf8: UTF8): Uint8Array {
|
|
43
|
+
return new TextEncoder().encode(utf8);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// --> HEX
|
|
47
|
+
export function utf8ToHex(utf8: UTF8): Hex {
|
|
48
|
+
const bytes = utf8ToBytes(utf8);
|
|
49
|
+
return bytesToHex(bytes);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// --> BASE64
|
|
53
|
+
export function utf8ToBase64(utf8: UTF8): Base64 {
|
|
54
|
+
const bytes = utf8ToBytes(utf8);
|
|
55
|
+
return bytesToBase64(bytes);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// --> BASE64URL
|
|
59
|
+
export function utf8ToBase64URL(utf8: UTF8): Base64 {
|
|
60
|
+
const bytes = utf8ToBytes(utf8);
|
|
61
|
+
return bytesToBase64URL(bytes);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/////////////////////////////////////////////////////////////////////
|
|
65
|
+
/////// HEX --> X
|
|
66
|
+
/////////////////////////////////////////////////////////////////////
|
|
67
|
+
|
|
68
|
+
// --> BYTES
|
|
69
|
+
export function hexToBytes(hex: Hex): Uint8Array {
|
|
70
|
+
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
71
|
+
const bytes =
|
|
72
|
+
cleanHex.match(/.{1,2}/g)?.map((byte) => Number.parseInt(byte, 16)) || [];
|
|
73
|
+
return new Uint8Array(bytes);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// --> UTF8
|
|
77
|
+
export function hexToUTF8(hex: Hex): UTF8 {
|
|
78
|
+
const bytes = hexToBytes(hex);
|
|
79
|
+
return bytesToUTF8(bytes);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// --> BASE64
|
|
83
|
+
export function hexToBase64(hex: Hex): Base64 {
|
|
84
|
+
const bytes = hexToBytes(hex);
|
|
85
|
+
return bytesToBase64(bytes);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// --> BASE64URL
|
|
89
|
+
export function hexToBase64URL(hex: Hex): Base64 {
|
|
90
|
+
const bytes = hexToBytes(hex);
|
|
91
|
+
return bytesToBase64URL(bytes);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/////////////////////////////////////////////////////////////////////
|
|
95
|
+
/////// BASE64 --> X
|
|
96
|
+
/////////////////////////////////////////////////////////////////////
|
|
97
|
+
|
|
98
|
+
// --> BYTES
|
|
99
|
+
export function base64ToBytes(base64: Base64): Uint8Array {
|
|
100
|
+
return Uint8Array.from(atob(base64), (m) => m.codePointAt(0) || 0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// --> UTF8
|
|
104
|
+
export function base64ToUTF8(base64: Base64): UTF8 {
|
|
105
|
+
const bytes = base64ToBytes(base64);
|
|
106
|
+
return bytesToUTF8(bytes);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// --> HEX
|
|
110
|
+
export function base64ToHex(base64: Base64): Hex {
|
|
111
|
+
const bytes = base64ToBytes(base64);
|
|
112
|
+
return bytesToHex(bytes);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// --> BASE64URL
|
|
116
|
+
export function base64ToBase64URL(base64: Base64): Base64 {
|
|
117
|
+
return base64
|
|
118
|
+
.replace(/[\r\n\t ]+/g, "")
|
|
119
|
+
.replace(/\+/g, "-")
|
|
120
|
+
.replace(/\//g, "_")
|
|
121
|
+
.replace(/=+$/, "");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/////////////////////////////////////////////////////////////////////
|
|
125
|
+
/////// BASE64URL --> X
|
|
126
|
+
/////////////////////////////////////////////////////////////////////
|
|
127
|
+
|
|
128
|
+
// --> BYTES
|
|
129
|
+
export function base64URLToBytes(base64URL: Base64URL): Uint8Array {
|
|
130
|
+
const base64 = base64URLToBase64(base64URL);
|
|
131
|
+
return base64ToBytes(base64);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// --> UTF8
|
|
135
|
+
export function base64URLToUTF8(base64URL: Base64URL): UTF8 {
|
|
136
|
+
const bytes = base64URLToBytes(base64URL);
|
|
137
|
+
return bytesToUTF8(bytes);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// --> HEX
|
|
141
|
+
export function base64URLToHex(base64URL: Base64URL): Hex {
|
|
142
|
+
const bytes = base64URLToBytes(base64URL);
|
|
143
|
+
return bytesToHex(bytes);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// --> BASE64
|
|
147
|
+
export function base64URLToBase64(base64URL: Base64URL): Base64 {
|
|
148
|
+
return base64URL
|
|
149
|
+
.padEnd(base64URL.length + ((4 - (base64URL.length % 4)) % 4), "=")
|
|
150
|
+
.replace(/-/g, "+")
|
|
151
|
+
.replace(/_/g, "/");
|
|
152
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks the client cookie for a specific name. Returns the value if
|
|
3
|
+
* found, otherwise undefined. Does not do any encoding or decoding.
|
|
4
|
+
*/
|
|
5
|
+
export function getClientCookie(name: string) {
|
|
6
|
+
const match = document.cookie.match(new RegExp(`(^| )${name}=([^;]*)`));
|
|
7
|
+
return match ? match[2] : undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Sets a client cookie with the specified name and value. The cookie
|
|
12
|
+
* is set to expire in one year and is accessible to all paths on the
|
|
13
|
+
* domain. The SameSite attribute is set to Lax. Does not do any
|
|
14
|
+
* encoding or decoding.
|
|
15
|
+
*/
|
|
16
|
+
export function setClientCookie(name: string, value: string) {
|
|
17
|
+
document.cookie = `${name}=${value}; path=/; max-age=31536000; SameSite=Lax`;
|
|
18
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getClientCookie } from "vorma/kit/cookies";
|
|
2
|
+
|
|
3
|
+
export function getCSRFToken(opts: {
|
|
4
|
+
isDev: boolean;
|
|
5
|
+
cookieName?: string;
|
|
6
|
+
}): string | undefined {
|
|
7
|
+
const prefix = opts.isDev ? "__Dev-" : "__Host-";
|
|
8
|
+
const name = opts.cookieName || "csrf_token";
|
|
9
|
+
return getClientCookie(prefix + name);
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type Fn = (...args: Array<any>) => any;
|
|
2
|
+
|
|
3
|
+
export function debounce<T extends Fn>(
|
|
4
|
+
fn: T,
|
|
5
|
+
delayInMs: number,
|
|
6
|
+
): (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>> {
|
|
7
|
+
let timeoutID: number;
|
|
8
|
+
|
|
9
|
+
return (...args: Parameters<T>) => {
|
|
10
|
+
return new Promise<Awaited<ReturnType<T>>>((resolve) => {
|
|
11
|
+
clearTimeout(timeoutID);
|
|
12
|
+
timeoutID = window.setTimeout(() => {
|
|
13
|
+
resolve(fn(...args));
|
|
14
|
+
}, delayInMs);
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performs a deep equality comparison of two JSON-compatible values.
|
|
3
|
+
* Handles null, undefined, primitives, arrays, and plain objects, recursively.
|
|
4
|
+
* Does not support Maps, Sets, Functions, or other non-JSON types.
|
|
5
|
+
*/
|
|
6
|
+
export function jsonDeepEquals(a: unknown, b: unknown): boolean {
|
|
7
|
+
// Tautology
|
|
8
|
+
if (a === b) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// If both were null or both were undefined, we would have early returned above.
|
|
13
|
+
// So if either at this point is loosely null, we know they're not equal.
|
|
14
|
+
if (a == null || b == null) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// If types are different, we know they're not equal.
|
|
19
|
+
if (typeof a !== typeof b) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const aIsArray = Array.isArray(a);
|
|
24
|
+
const bIsArray = Array.isArray(b);
|
|
25
|
+
|
|
26
|
+
// If one is an array and the other is not, we know they're not equal.
|
|
27
|
+
if (aIsArray !== bIsArray) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Handle arrays
|
|
32
|
+
if (aIsArray && bIsArray) {
|
|
33
|
+
if (a.length !== b.length) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return a.every((item, index) => jsonDeepEquals(item, b[index]));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Handle objects
|
|
40
|
+
if (typeof a === "object" && typeof b === "object") {
|
|
41
|
+
const aKeys = Object.keys(a as object);
|
|
42
|
+
const bKeys = Object.keys(b as object);
|
|
43
|
+
|
|
44
|
+
if (aKeys.length !== bKeys.length) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return aKeys.every((key) => {
|
|
49
|
+
return Object.hasOwn(b, key) && jsonDeepEquals((a as any)[key], (b as any)[key]);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export function serializeToSearchParams(obj: Record<any, any>): URLSearchParams {
|
|
2
|
+
const params = new URLSearchParams();
|
|
3
|
+
|
|
4
|
+
function appendValue(key: string, value: any) {
|
|
5
|
+
if (value === null || value === undefined) {
|
|
6
|
+
params.append(key, "");
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (Array.isArray(value)) {
|
|
11
|
+
if (value.length === 0) {
|
|
12
|
+
params.append(key, "");
|
|
13
|
+
} else {
|
|
14
|
+
for (const item of value) {
|
|
15
|
+
appendValue(key, item);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (typeof value === "object") {
|
|
22
|
+
const entries = Object.entries(value);
|
|
23
|
+
if (entries.length === 0) {
|
|
24
|
+
params.append(key, "");
|
|
25
|
+
} else {
|
|
26
|
+
// Sort nested keys alphabetically
|
|
27
|
+
entries.sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
|
|
28
|
+
for (const [subKey, subValue] of entries) {
|
|
29
|
+
const newKey = key ? `${key}.${subKey}` : subKey;
|
|
30
|
+
appendValue(newKey, subValue);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
params.append(key, String(value));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (typeof obj === "object" && obj !== null) {
|
|
40
|
+
// Sort top-level keys alphabetically
|
|
41
|
+
const entries = Object.entries(obj);
|
|
42
|
+
entries.sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
|
|
43
|
+
for (const [key, value] of entries) {
|
|
44
|
+
appendValue(key, value);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return params;
|
|
49
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministically serializes a JSON-compatible value to a stable string.
|
|
3
|
+
* Throws if it detects a circular reference. Does not support Maps, Sets,
|
|
4
|
+
* Functions, or other non-JSON types.
|
|
5
|
+
*/
|
|
6
|
+
export function jsonStringifyStable(input: unknown): string {
|
|
7
|
+
// First stabilize the structure, then JSON.stringify
|
|
8
|
+
const stabilized = stabilizeStructure(input, new WeakSet());
|
|
9
|
+
|
|
10
|
+
return JSON.stringify(stabilized);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function stabilizeStructure(value: unknown, visited: WeakSet<object>): unknown {
|
|
14
|
+
// Handle primitives and null
|
|
15
|
+
if (value === null || typeof value !== "object") {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Prevent circular references
|
|
20
|
+
if (visited.has(value)) {
|
|
21
|
+
throw new Error("Circular reference detected during stable JSON stringification");
|
|
22
|
+
}
|
|
23
|
+
visited.add(value);
|
|
24
|
+
|
|
25
|
+
// Handle arrays - recursively stabilize each element
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
const result = value.map((item) => stabilizeStructure(item, visited));
|
|
28
|
+
visited.delete(value); // Clean up after processing
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Handle objects - sort keys and recursively stabilize values
|
|
33
|
+
const keys = Object.keys(value).sort();
|
|
34
|
+
const stable: Record<string, unknown> = {};
|
|
35
|
+
|
|
36
|
+
// Add sorted keys with stabilized values
|
|
37
|
+
for (const key of keys) {
|
|
38
|
+
stable[key] = stabilizeStructure((value as Record<string, unknown>)[key], visited);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
visited.delete(value); // Clean up after processing
|
|
42
|
+
return stable;
|
|
43
|
+
}
|