@real-router/browser-plugin 0.7.0 → 0.9.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/README.md +12 -30
- package/dist/cjs/index.d.ts +7 -153
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/metafile-cjs.json +1 -1
- package/dist/esm/index.d.mts +7 -153
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/metafile-esm.json +1 -1
- package/package.json +5 -4
- package/src/constants.ts +2 -36
- package/src/factory.ts +27 -58
- package/src/index.ts +3 -1
- package/src/plugin.ts +62 -206
- package/src/types.ts +2 -179
- package/src/url-utils.ts +12 -80
- package/src/validation.ts +7 -63
- package/src/browser.ts +0 -128
- package/src/popstate-utils.ts +0 -60
package/src/browser.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
// packages/browser-plugin/modules/browser.ts
|
|
2
|
-
|
|
3
|
-
import { logger } from "@real-router/logger";
|
|
4
|
-
|
|
5
|
-
import { LOGGER_CONTEXT } from "./constants";
|
|
6
|
-
import { createRegExpCache, extractPath } from "./url-utils";
|
|
7
|
-
|
|
8
|
-
import type { Browser, BrowserPluginOptions, URLParseOptions } from "./types";
|
|
9
|
-
import type { State } from "@real-router/core";
|
|
10
|
-
|
|
11
|
-
/** No-operation cleanup function for fallback browser */
|
|
12
|
-
const NOOP = (): void => {};
|
|
13
|
-
|
|
14
|
-
const pushState = (state: State, path: string) => {
|
|
15
|
-
globalThis.history.pushState(state, "", path);
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const replaceState = (state: State, path: string) => {
|
|
19
|
-
globalThis.history.replaceState(state, "", path);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const addPopstateListener: Browser["addPopstateListener"] = (fn) => {
|
|
23
|
-
globalThis.addEventListener("popstate", fn);
|
|
24
|
-
|
|
25
|
-
return () => {
|
|
26
|
-
globalThis.removeEventListener("popstate", fn);
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const regExpCache = createRegExpCache();
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Safely encodes/decodes path to normalize URL encoding
|
|
34
|
-
*
|
|
35
|
-
* @param path - Path to normalize
|
|
36
|
-
* @returns Normalized path or original on error
|
|
37
|
-
*/
|
|
38
|
-
const safelyEncodePath = (path: string): string => {
|
|
39
|
-
try {
|
|
40
|
-
return encodeURI(decodeURI(path));
|
|
41
|
-
} catch (error) {
|
|
42
|
-
logger.warn(LOGGER_CONTEXT, `Could not encode path "${path}"`, error);
|
|
43
|
-
|
|
44
|
-
return path;
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const getLocation = (opts: BrowserPluginOptions) => {
|
|
49
|
-
const rawPath = extractPath(
|
|
50
|
-
globalThis.location.pathname,
|
|
51
|
-
globalThis.location.hash,
|
|
52
|
-
opts as URLParseOptions,
|
|
53
|
-
regExpCache,
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
return safelyEncodePath(rawPath) + globalThis.location.search;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Gets current URL hash
|
|
61
|
-
*/
|
|
62
|
-
const getHash = () => globalThis.location.hash;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Creates a fallback browser for non-browser environments (SSR).
|
|
66
|
-
* Logs warning on first method call to help diagnose misconfiguration.
|
|
67
|
-
*
|
|
68
|
-
* @returns Browser API with no-op implementations
|
|
69
|
-
*/
|
|
70
|
-
function createFallbackBrowser(): Browser {
|
|
71
|
-
let hasWarned = false;
|
|
72
|
-
|
|
73
|
-
const warnOnce = (method: string) => {
|
|
74
|
-
if (!hasWarned) {
|
|
75
|
-
logger.warn(
|
|
76
|
-
LOGGER_CONTEXT,
|
|
77
|
-
`Browser plugin is running in a non-browser environment. ` +
|
|
78
|
-
`Method "${method}" is a no-op. ` +
|
|
79
|
-
`This is expected for SSR, but may indicate misconfiguration if you expected browser behavior.`,
|
|
80
|
-
);
|
|
81
|
-
hasWarned = true;
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
pushState: () => {
|
|
87
|
-
warnOnce("pushState");
|
|
88
|
-
},
|
|
89
|
-
replaceState: () => {
|
|
90
|
-
warnOnce("replaceState");
|
|
91
|
-
},
|
|
92
|
-
addPopstateListener: () => {
|
|
93
|
-
warnOnce("addPopstateListener");
|
|
94
|
-
|
|
95
|
-
return NOOP;
|
|
96
|
-
},
|
|
97
|
-
getLocation: () => {
|
|
98
|
-
warnOnce("getLocation");
|
|
99
|
-
|
|
100
|
-
return "";
|
|
101
|
-
},
|
|
102
|
-
getHash: () => {
|
|
103
|
-
warnOnce("getHash");
|
|
104
|
-
|
|
105
|
-
return "";
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Creates browser API abstraction that works in both browser and SSR environments
|
|
112
|
-
*
|
|
113
|
-
* @returns Browser API object
|
|
114
|
-
*/
|
|
115
|
-
export function createSafeBrowser(): Browser {
|
|
116
|
-
const isBrowser =
|
|
117
|
-
typeof globalThis.window !== "undefined" && !!globalThis.history;
|
|
118
|
-
|
|
119
|
-
return isBrowser
|
|
120
|
-
? {
|
|
121
|
-
pushState,
|
|
122
|
-
replaceState,
|
|
123
|
-
addPopstateListener,
|
|
124
|
-
getLocation,
|
|
125
|
-
getHash,
|
|
126
|
-
}
|
|
127
|
-
: createFallbackBrowser();
|
|
128
|
-
}
|
package/src/popstate-utils.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { isStateStrict as isState } from "type-guards";
|
|
2
|
-
|
|
3
|
-
import type { BrowserPluginOptions, Browser } from "./types";
|
|
4
|
-
import type { PluginApi, State, Params } from "@real-router/core";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Extracts route name and params from a popstate event.
|
|
8
|
-
*
|
|
9
|
-
* - If history.state is a valid router state → returns name/params from it
|
|
10
|
-
* - If not (e.g. manually entered URL) → matches current URL against route tree
|
|
11
|
-
* - Returns undefined if no route matches
|
|
12
|
-
*
|
|
13
|
-
* @param evt - PopStateEvent from browser
|
|
14
|
-
* @param api - PluginApi instance
|
|
15
|
-
* @param browser - Browser API instance
|
|
16
|
-
* @param options - Browser plugin options
|
|
17
|
-
* @returns Route identifier or undefined
|
|
18
|
-
*/
|
|
19
|
-
export function getRouteFromEvent(
|
|
20
|
-
evt: PopStateEvent,
|
|
21
|
-
api: PluginApi,
|
|
22
|
-
browser: Browser,
|
|
23
|
-
options: BrowserPluginOptions,
|
|
24
|
-
): { name: string; params: Params } | undefined {
|
|
25
|
-
if (isState(evt.state)) {
|
|
26
|
-
return { name: evt.state.name, params: evt.state.params };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const state = api.matchPath(browser.getLocation(options));
|
|
30
|
-
|
|
31
|
-
return state ? { name: state.name, params: state.params } : undefined;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Updates browser state (pushState or replaceState)
|
|
36
|
-
*
|
|
37
|
-
* @param state - Router state
|
|
38
|
-
* @param url - URL to set
|
|
39
|
-
* @param replace - Whether to replace instead of push
|
|
40
|
-
* @param browser - Browser API instance
|
|
41
|
-
*/
|
|
42
|
-
export function updateBrowserState(
|
|
43
|
-
state: State,
|
|
44
|
-
url: string,
|
|
45
|
-
replace: boolean,
|
|
46
|
-
browser: Browser,
|
|
47
|
-
): void {
|
|
48
|
-
const historyState = {
|
|
49
|
-
meta: state.meta,
|
|
50
|
-
name: state.name,
|
|
51
|
-
params: state.params,
|
|
52
|
-
path: state.path,
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
if (replace) {
|
|
56
|
-
browser.replaceState(historyState, url);
|
|
57
|
-
} else {
|
|
58
|
-
browser.pushState(historyState, url);
|
|
59
|
-
}
|
|
60
|
-
}
|