react-routes-forge 1.0.3

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mostafa Abdelhamid
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,170 @@
1
+ # react-routes-forge
2
+
3
+ Type-safe route definitions with automatic path builders for React apps.
4
+
5
+ ## Why react-routes-forge?
6
+
7
+ `react-routes-forge` eliminates the duplicate template/builder pattern used in route definitions. One source of truth defines:
8
+
9
+ - static path templates for routing
10
+ - dynamic path builders for navigation
11
+ - typed params for safer runtime usage
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install react-routes-forge
17
+ ```
18
+
19
+ ## Quick start
20
+
21
+ ```ts
22
+ import { defineRoutes } from "react-routes-forge";
23
+
24
+ export const PATHS = defineRoutes({
25
+ HOME: "/",
26
+ LOGIN: "/login",
27
+ USERS: {
28
+ ROOT: "/users",
29
+ ADD: "/users/add",
30
+ EDIT: "/users/edit/:id",
31
+ DETAILS: "/users/:id",
32
+ },
33
+ ROLES: {
34
+ PERMISSIONS: "/roles/permissions/:name",
35
+ },
36
+ } as const);
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ### Router definitions
42
+
43
+ Use route templates directly in route declarations.
44
+
45
+ ```tsx
46
+ import { PATHS } from './paths';
47
+
48
+ <Route path={PATHS.HOME} />
49
+ <Route path={PATHS.USERS.EDIT} />
50
+ <Route path={PATHS.ROLES.PERMISSIONS} />
51
+ ```
52
+
53
+ ### Navigation
54
+
55
+ Build resolved paths from dynamic templates.
56
+
57
+ ```ts
58
+ navigate(PATHS.USERS.EDIT.build({ id: 42 }));
59
+ navigate(PATHS.ROLES.PERMISSIONS.build({ name: "admin" }));
60
+ navigate(PATHS.HOME);
61
+ ```
62
+
63
+ ### Dynamic routes keep plain-string behavior
64
+
65
+ Dynamic routes remain usable as strings while gaining helper methods.
66
+
67
+ ```ts
68
+ PATHS.USERS.EDIT; // '/users/edit/:id'
69
+ PATHS.USERS.EDIT.build({ id: 42 }); // '/users/edit/42'
70
+ PATHS.USERS.EDIT.paramNames; // ['id']
71
+ ```
72
+
73
+ ## API
74
+
75
+ ### `defineRoutes(routeMap)`
76
+
77
+ Create a typed route object from a nested route definition.
78
+
79
+ - static routes remain plain strings
80
+ - dynamic routes gain `.build(params)` and `.paramNames`
81
+
82
+ ### `build(template, params)`
83
+
84
+ Resolve a route template without using `defineRoutes`.
85
+
86
+ ```ts
87
+ import { build } from "react-routes-forge";
88
+
89
+ build("/users/:id/posts/:postId", { id: 1, postId: 42 });
90
+ // '/users/1/posts/42'
91
+ ```
92
+
93
+ ### `isActivePath(currentPath, template, options?)`
94
+
95
+ Check whether a path matches a template.
96
+
97
+ ```ts
98
+ import { isActivePath } from "react-routes-forge";
99
+
100
+ isActivePath("/users/42", "/users/:id");
101
+ isActivePath("/users/42/posts", "/users/:id");
102
+ isActivePath("/users/42/posts", "/users/:id", { exact: false });
103
+ ```
104
+
105
+ ### `extractParamsFromPath(template, resolvedPath)`
106
+
107
+ Extract path params from a resolved route.
108
+
109
+ ```ts
110
+ import { extractParamsFromPath } from "react-routes-forge";
111
+
112
+ extractParamsFromPath("/users/:id", "/users/42");
113
+ // { id: '42' }
114
+ ```
115
+
116
+ ### `joinPaths(...segments)`
117
+
118
+ Join path fragments and normalise slashes.
119
+
120
+ ```ts
121
+ import { joinPaths } from "react-routes-forge";
122
+
123
+ joinPaths("/api/", "/v1/", "/users");
124
+ // '/api/v1/users'
125
+ ```
126
+
127
+ ### `getParamNames(template)`
128
+
129
+ Return all parameter names from a template.
130
+
131
+ ```ts
132
+ import { getParamNames } from "react-routes-forge";
133
+
134
+ getParamNames("/users/:id/posts/:postId");
135
+ // ['id', 'postId']
136
+ ```
137
+
138
+ ## React hooks
139
+
140
+ Import only when using React Router.
141
+
142
+ ### `useRouteParams<T>()`
143
+
144
+ Typed wrapper around React Router's `useParams`.
145
+
146
+ ```tsx
147
+ import { useRouteParams } from "react-routes-forge";
148
+
149
+ function EditUser() {
150
+ const { id } = useRouteParams<"/users/edit/:id">();
151
+ return <div>{id}</div>;
152
+ }
153
+ ```
154
+
155
+ ### `useNavigateTo()`
156
+
157
+ Thin, typed wrapper around React Router's `useNavigate()`.
158
+
159
+ ```tsx
160
+ import { useNavigateTo } from "react-routes-forge";
161
+
162
+ function Component() {
163
+ const navigateTo = useNavigateTo();
164
+ return (
165
+ <button onClick={() => navigateTo(PATHS.USERS.EDIT.build({ id: 42 }))}>
166
+ Edit
167
+ </button>
168
+ );
169
+ }
170
+ ```
@@ -0,0 +1,107 @@
1
+ /**
2
+ * A static route string (template or resolved), e.g. '/users/:id' or '/users/42'
3
+ */
4
+ type RoutePath = `/${string}`;
5
+ /**
6
+ * A route builder function that accepts params and returns a resolved path.
7
+ */
8
+ type RouteBuilder<TParams extends RouteParams = RouteParams> = (params: TParams) => RoutePath;
9
+ /**
10
+ * Acceptable param value types for route builders.
11
+ */
12
+ type RouteParam = string | number;
13
+ type RouteParams = Record<string, RouteParam>;
14
+ /**
15
+ * A leaf node in a route definition: either a static path or a builder function.
16
+ */
17
+ type RouteLeaf = RoutePath | RouteBuilder;
18
+ /**
19
+ * Recursively defines a route map: each key is either a leaf or a nested map.
20
+ */
21
+ type RouteMap = {
22
+ [key: string]: RouteLeaf | RouteMap;
23
+ };
24
+ /**
25
+ * Extracts param names from a path template string.
26
+ * e.g. '/users/:id/posts/:postId' → 'id' | 'postId'
27
+ */
28
+ type ExtractParams<T extends string> = T extends `${string}:${infer Param}/${infer Rest}` ? Param | ExtractParams<`/${Rest}`> : T extends `${string}:${infer Param}` ? Param : never;
29
+ /**
30
+ * Builds a params object type from a path template.
31
+ * e.g. '/users/:id' → { id: RouteParam }
32
+ */
33
+ type PathParams<T extends string> = ExtractParams<T> extends never ? never : {
34
+ [K in ExtractParams<T>]: RouteParam;
35
+ };
36
+
37
+ declare function buildPath(template: string, params: Record<string, RouteParam>): string;
38
+ declare function extractParamNames(template: string): string[];
39
+ declare function isDynamic(path: string): boolean;
40
+ declare function isActivePath(currentPath: string, template: string, options?: {
41
+ exact?: boolean;
42
+ }): boolean;
43
+ declare function extractParamsFromPath(template: string, resolvedPath: string): Record<string, string>;
44
+ declare function joinPaths(...segments: string[]): string;
45
+ declare function build(template: string, params: Record<string, RouteParam>): string;
46
+ declare function getParamNames(template: string): string[];
47
+
48
+ type RouteInput = {
49
+ [key: string]: string | RouteInput;
50
+ };
51
+ type DynamicRoute<T extends string> = T extends `${string}:${string}` ? T & {
52
+ build(params: PathParams<T>): RoutePath;
53
+ paramNames: Array<ExtractParams<T>>;
54
+ } : T;
55
+ type ResolvedRoutes<T extends RouteInput> = {
56
+ [K in keyof T]: T[K] extends RouteInput ? ResolvedRoutes<T[K]> : T[K] extends string ? DynamicRoute<T[K]> : never;
57
+ };
58
+ declare function defineRoutes<T extends RouteInput>(routes: T): ResolvedRoutes<T>;
59
+
60
+ /**
61
+ * React integration hooks for route-forge.
62
+ * These are thin wrappers — import only if you're using React Router.
63
+ */
64
+
65
+ /**
66
+ * A typed wrapper around React Router's `useParams`.
67
+ *
68
+ * Pass the route's path template as a const generic to get a properly typed
69
+ * params object back — no casting needed.
70
+ *
71
+ * @example
72
+ * ```tsx
73
+ * // Route is defined as '/users/edit/:id'
74
+ * const { id } = useRouteParams<'/users/edit/:id'>();
75
+ * ```
76
+ */
77
+ declare function useRouteParams<T extends string, K extends string = T extends `${string}:${infer P}/${infer R}` ? P | (R extends `${string}:${infer Q}` ? Q : never) : T extends `${string}:${infer P}` ? P : never>(): Record<K, string>;
78
+ type NavigateOptions = {
79
+ replace?: boolean;
80
+ state?: unknown;
81
+ };
82
+ /**
83
+ * A typed `navigate` helper that accepts a resolved path (output of `.build()`)
84
+ * or a plain static path, with optional navigation options.
85
+ *
86
+ * @example
87
+ * ```tsx
88
+ * const navigateTo = useNavigateTo();
89
+ * navigateTo(PATHS.USERS.EDIT.build({ id: 42 }));
90
+ * navigateTo(PATHS.HOME, { replace: true });
91
+ * ```
92
+ */
93
+ declare function useNavigateTo(): (path: string, options?: NavigateOptions) => void;
94
+ /**
95
+ * Resolves a dynamic path template against params using React Router's
96
+ * `generatePath`, with proper typing.
97
+ *
98
+ * Useful when you need the resolved path string without navigating.
99
+ *
100
+ * @example
101
+ * ```tsx
102
+ * const path = useResolvedPath('/users/:id', { id: 42 }); // → '/users/42'
103
+ * ```
104
+ */
105
+ declare function useResolvedPath(template: string, params: Record<string, RouteParam>): string;
106
+
107
+ export { type ExtractParams, type PathParams, type RouteBuilder, type RouteLeaf, type RouteMap, type RouteParam, type RouteParams, type RoutePath, build, buildPath, defineRoutes, extractParamNames, extractParamsFromPath, getParamNames, isActivePath, isDynamic, joinPaths, useNavigateTo, useResolvedPath, useRouteParams };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var c=()=>/:([^/]+)/g,f=()=>/[.*+?^${}()|[\]\\]/g;function g(t){return t.replace(f(),"\\$&")}function R(t){return g(t).replace(c(),"([^/]+)")}function i(t,e){let r=a(t).reduce((u,s)=>{let p=e[s],x=p===void 0?`:${s}`:String(p);return u.replace(new RegExp(`:${g(s)}(?=/|$)`,"g"),x)},t);return globalThis.process?.env?.NODE_ENV!=="production"&&r.includes(":")&&console.warn(`[route-forge] Unresolved params in path "${r}". Check that all :param segments have matching keys.`),r}function a(t){return[...t.matchAll(c())].map(e=>e[1])}function m(t){return c().test(t)}function d(t,e,n={exact:!0}){let r=R(e);return(n.exact?new RegExp(`^${r}$`):new RegExp(`^${r}`)).test(t)}function l(t,e){let n=a(t),r=new RegExp(`^${R(t)}$`),o=e.match(r);return o?Object.fromEntries(n.map((u,s)=>[u,o[s+1]??""])):{}}function T(...t){return"/"+t.map(e=>e.replace(/^\/+|\/+$/g,"")).filter(Boolean).join("/")}function y(t,e){return i(t,e)}function h(t){return a(t)}var v=t=>typeof t=="object"&&t!==null;function $(t){let e=a(t),n=new String(t);return n.build=r=>i(t,r),n.paramNames=e,n}function P(t){let e={};for(let n in t){if(!Object.prototype.hasOwnProperty.call(t,n))continue;let r=t[n];typeof r=="string"?e[n]=m(r)?$(r):r:v(r)&&(e[n]=P(r))}return e}function b(t){return P(t)}import{useParams as N,useNavigate as E,generatePath as w}from"react-router-dom";function k(){return N()}function D(){let t=E();return(e,n)=>{t(e,n)}}function A(t,e){return w(t,Object.fromEntries(Object.entries(e).map(([n,r])=>[n,String(r)])))}export{y as build,i as buildPath,b as defineRoutes,a as extractParamNames,l as extractParamsFromPath,h as getParamNames,d as isActivePath,m as isDynamic,T as joinPaths,D as useNavigateTo,A as useResolvedPath,k as useRouteParams};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/utils.ts","../src/core/defineRoutes.ts","../src/hooks/index.ts"],"sourcesContent":["import type { RouteParam } from '../types';\n\n/** Returns a fresh RegExp each call — avoids shared `lastIndex` state on /g patterns. */\nconst PATH_PARAM_RE = () => /:([^/]+)/g;\nconst ESCAPE_RE = () => /[.*+?^${}()|[\\]\\\\]/g;\n\nfunction escapeRegex(value: string): string {\n return value.replace(ESCAPE_RE(), '\\\\$&');\n}\n\nfunction createTemplatePattern(template: string): string {\n return escapeRegex(template).replace(PATH_PARAM_RE(), '([^/]+)');\n}\n\nexport function buildPath(\n template: string,\n params: Record<string, RouteParam>\n): string {\n const paramNames = extractParamNames(template);\n\n const resolved = paramNames.reduce((path, name) => {\n const value = params[name];\n const replacement = value === undefined ? `:${name}` : String(value);\n return path.replace(new RegExp(`:${escapeRegex(name)}(?=/|$)`, 'g'), replacement);\n }, template);\n\n const runtimeProcess = (globalThis as typeof globalThis & {\n process?: {\n env?: Record<string, string | undefined>;\n };\n }).process;\n\n if (runtimeProcess?.env?.NODE_ENV !== 'production' && resolved.includes(':')) {\n console.warn(\n `[route-forge] Unresolved params in path \"${resolved}\". ` +\n `Check that all :param segments have matching keys.`\n );\n }\n\n return resolved;\n}\n\nexport function extractParamNames(template: string): string[] {\n return [...template.matchAll(PATH_PARAM_RE())].map((match) => match[1] as string);\n}\n\nexport function isDynamic(path: string): boolean {\n return PATH_PARAM_RE().test(path);\n}\n\nexport function isActivePath(\n currentPath: string,\n template: string,\n options: { exact?: boolean } = { exact: true }\n): boolean {\n const pattern = createTemplatePattern(template);\n const regex = options.exact\n ? new RegExp(`^${pattern}$`)\n : new RegExp(`^${pattern}`);\n\n return regex.test(currentPath);\n}\n\nexport function extractParamsFromPath(\n template: string,\n resolvedPath: string\n): Record<string, string> {\n const paramNames = extractParamNames(template);\n const regex = new RegExp(`^${createTemplatePattern(template)}$`);\n const match = resolvedPath.match(regex);\n\n if (!match) return {};\n\n return Object.fromEntries(\n paramNames.map((name, index) => [name, match[index + 1] ?? ''])\n );\n}\n\nexport function joinPaths(...segments: string[]): string {\n return (\n '/' +\n segments\n .map((segment) => segment.replace(/^\\/+|\\/+$/g, ''))\n .filter(Boolean)\n .join('/')\n );\n}\n\nexport function build(\n template: string,\n params: Record<string, RouteParam>\n): string {\n return buildPath(template, params);\n}\n\nexport function getParamNames(template: string): string[] {\n return extractParamNames(template);\n}\n","import { buildPath, extractParamNames, isDynamic } from './utils';\nimport type { ExtractParams, PathParams, RoutePath } from '../types';\n\n// Re-export so consumers that import from 'core/defineRoutes' get the full surface\nexport { buildPath, extractParamNames, isDynamic } from './utils';\n\ntype RouteInput = {\n [key: string]: string | RouteInput;\n};\n\ntype DynamicRoute<T extends string> = T extends `${string}:${string}`\n ? T & {\n build(params: PathParams<T>): RoutePath;\n paramNames: Array<ExtractParams<T>>;\n }\n : T;\n\ntype ResolvedRoutes<T extends RouteInput> = {\n [K in keyof T]: T[K] extends RouteInput\n ? ResolvedRoutes<T[K]>\n : T[K] extends string\n ? DynamicRoute<T[K]>\n : never;\n};\n\nconst isRouteGroup = (value: unknown): value is RouteInput =>\n typeof value === 'object' && value !== null;\n\nfunction wrapDynamicPath<T extends string>(template: T): DynamicRoute<T> {\n const paramNames = extractParamNames(template);\n const wrapped = new String(template) as unknown as DynamicRoute<T> & {\n build: (params: PathParams<T>) => RoutePath;\n paramNames: Array<ExtractParams<T>>;\n };\n\n wrapped.build = (params: PathParams<T>) => buildPath(template, params) as RoutePath;\n wrapped.paramNames = paramNames as Array<ExtractParams<T>>;\n\n return wrapped as unknown as DynamicRoute<T>;\n}\n\nfunction processRouteMap<T extends RouteInput>(routes: T): ResolvedRoutes<T> {\n const result = {} as ResolvedRoutes<T>;\n\n for (const key in routes) {\n if (!Object.prototype.hasOwnProperty.call(routes, key)) continue;\n\n const value = routes[key];\n\n if (typeof value === 'string') {\n result[key] = (isDynamic(value)\n ? wrapDynamicPath(value)\n : value) as ResolvedRoutes<T>[typeof key];\n } else if (isRouteGroup(value)) {\n result[key] = processRouteMap(value as RouteInput) as unknown as ResolvedRoutes<T>[typeof key];\n }\n }\n\n return result;\n}\n\nexport function defineRoutes<T extends RouteInput>(routes: T): ResolvedRoutes<T> {\n return processRouteMap(routes);\n}\n","/**\n * React integration hooks for route-forge.\n * These are thin wrappers — import only if you're using React Router.\n */\n\nimport { useParams, useNavigate, generatePath } from 'react-router-dom';\nimport type { RouteParam } from '../types';\n\n// ─── useRouteParams ──────────────────────────────────────────────────────────\n\n/**\n * A typed wrapper around React Router's `useParams`.\n *\n * Pass the route's path template as a const generic to get a properly typed\n * params object back — no casting needed.\n *\n * @example\n * ```tsx\n * // Route is defined as '/users/edit/:id'\n * const { id } = useRouteParams<'/users/edit/:id'>();\n * ```\n */\nexport function useRouteParams<\n T extends string,\n // Extracts ':id' → 'id', ':postId' → 'postId', etc.\n K extends string = T extends `${string}:${infer P}/${infer R}`\n ? P | (R extends `${string}:${infer Q}` ? Q : never)\n : T extends `${string}:${infer P}`\n ? P\n : never,\n>(): Record<K, string> {\n return useParams() as Record<K, string>;\n}\n\n// ─── useNavigateTo ──────────────────────────────────────────────────────────\n\ntype NavigateOptions = {\n replace?: boolean;\n state?: unknown;\n};\n\n/**\n * A typed `navigate` helper that accepts a resolved path (output of `.build()`)\n * or a plain static path, with optional navigation options.\n *\n * @example\n * ```tsx\n * const navigateTo = useNavigateTo();\n * navigateTo(PATHS.USERS.EDIT.build({ id: 42 }));\n * navigateTo(PATHS.HOME, { replace: true });\n * ```\n */\nexport function useNavigateTo() {\n const navigate = useNavigate();\n\n return (path: string, options?: NavigateOptions) => {\n navigate(path, options);\n };\n}\n\n// ─── useResolvedPath ─────────────────────────────────────────────────────────\n\n/**\n * Resolves a dynamic path template against params using React Router's\n * `generatePath`, with proper typing.\n *\n * Useful when you need the resolved path string without navigating.\n *\n * @example\n * ```tsx\n * const path = useResolvedPath('/users/:id', { id: 42 }); // → '/users/42'\n * ```\n */\nexport function useResolvedPath(\n template: string,\n params: Record<string, RouteParam>\n): string {\n return generatePath(\n template,\n Object.fromEntries(Object.entries(params).map(([k, v]) => [k, String(v)]))\n );\n}\n"],"mappings":"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","names":["PATH_PARAM_RE","ESCAPE_RE","escapeRegex","value","createTemplatePattern","template","buildPath","params","resolved","extractParamNames","path","name","replacement","match","isDynamic","isActivePath","currentPath","options","pattern","extractParamsFromPath","resolvedPath","paramNames","regex","index","joinPaths","segments","segment","build","getParamNames","isRouteGroup","value","wrapDynamicPath","template","paramNames","extractParamNames","wrapped","params","buildPath","processRouteMap","routes","result","key","isDynamic","defineRoutes","useParams","useNavigate","generatePath","useRouteParams","useNavigateTo","navigate","path","options","useResolvedPath","template","params","k","v"]}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "react-routes-forge",
3
+ "version": "1.0.3",
4
+ "description": "Type-safe route definitions with automatic path builders for React apps",
5
+ "type": "module",
6
+ "author": {
7
+ "name": "Mostafa Abdelhamid",
8
+ "email": "mhsmustafa84@gmail.com"
9
+ },
10
+ "license": "MIT",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/mhsmustafa84/react-routes-forge.git"
14
+ },
15
+ "homepage": "https://github.com/mhsmustafa84/react-routes-forge#readme",
16
+ "bugs": "https://github.com/mhsmustafa84/react-routes-forge/issues",
17
+ "keywords": [
18
+ "react",
19
+ "router",
20
+ "routes",
21
+ "typescript",
22
+ "type-safe",
23
+ "react-router",
24
+ "path-builder"
25
+ ],
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "engines": {
30
+ "node": ">=18.0.0"
31
+ },
32
+ "sideEffects": false,
33
+ "exports": {
34
+ ".": {
35
+ "import": "./dist/index.js",
36
+ "types": "./dist/index.d.ts"
37
+ },
38
+ "./package.json": "./package.json"
39
+ },
40
+ "types": "./dist/index.d.ts",
41
+ "files": [
42
+ "dist",
43
+ "README.md",
44
+ "LICENSE"
45
+ ],
46
+ "scripts": {
47
+ "build": "tsup src/index.ts --format esm --dts --minify --sourcemap --clean",
48
+ "lint": "tsc --noEmit",
49
+ "test": "bun test",
50
+ "test:watch": "bun test --watch",
51
+ "prepare": "husky",
52
+ "prepublishOnly": "bun run test && bun run build",
53
+ "release": "standard-version"
54
+ },
55
+ "peerDependencies": {
56
+ "react": ">=17",
57
+ "react-router-dom": ">=6"
58
+ },
59
+ "peerDependenciesMeta": {
60
+ "react-router-dom": {
61
+ "optional": true
62
+ }
63
+ },
64
+ "devDependencies": {
65
+ "react-router-dom": "^6.0.0",
66
+ "@commitlint/cli": "^21.0.2",
67
+ "@commitlint/config-conventional": "^21.0.2",
68
+ "@types/node": "^26.1.1",
69
+ "@types/bun": "^1.3.14",
70
+ "husky": "^9.0.0",
71
+ "standard-version": "^9.5.0",
72
+ "tsup": "^8.0.0",
73
+ "typescript": "^5.0.0"
74
+ }
75
+ }