@native-router/core 1.3.0 → 1.4.1

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 CHANGED
@@ -59,9 +59,10 @@ commit(router, entry.task, entry.location); // commit like a click
59
59
  - Route guards: static `redirect` and async `beforeLoad` on every route level, run shallow → deep; more than 10 chained redirects reject with `RedirectLoopError`
60
60
  - Cancelable async navigation: a new resolve supersedes the in-flight one (`currentGuard`); `cancel()` aborts it; a history POP cancels it too. A superseded or cancelled `navigate()` promise **never settles** — don't `await` a navigation that might be superseded
61
61
  - Navigation API: `navigate`, `refresh`, `go`/`forward`/`back`, `commit`/`commitReplace`, `createHref`, `getParams`, `match`, `toLocation`, `resolve`, `resolveTo`
62
+ - Search validation via [Standard Schema](https://standardschema.dev): a `search` schema on any route level (zod/valibot/arktype, no hard dependency), parsed with `parseSearch`/`parseSearchSync`; failures throw `SearchError`
62
63
  - `preload(router, to, {ttl})`: resolve a target through the guards ahead of time, sharing one task across concurrent callers (in-flight dedup) with a TTL, default 30s; consumed entries are dropped on commit
63
64
  - `errorHandler` hook turns resolve failures into fallback views
64
- - Errors: `NativeRouterError`, `NotFoundError`, `RedirectLoopError`
65
+ - Errors: `NativeRouterError`, `NotFoundError`, `RedirectLoopError`, `SearchError`
65
66
  - Tree-shakable: `sideEffects: false`
66
67
 
67
68
  ## Matching semantics
@@ -73,6 +74,30 @@ commit(router, entry.task, entry.location); // commit like a click
73
74
  - Matching is **case-sensitive**.
74
75
  - Params of nested levels are merged **deep over shallow** (`mergeMatchedParams`): for `/:id` + `/posts/:id`, the deeper `id` wins.
75
76
 
77
+ ## Search validation
78
+
79
+ Declare a `search` validator on a route level and parse `location.search` with it in your `resolveView`. Any [Standard Schema](https://standardschema.dev) validator works — zod, valibot and arktype all implement the interface — so the core keeps zero extra runtime dependencies.
80
+
81
+ ```ts
82
+ import {create, parseSearch} from '@native-router/core';
83
+ import {z} from 'zod';
84
+
85
+ const listSearch = z.object({page: z.coerce.number().default(1)});
86
+
87
+ const router = create(
88
+ {path: '', children: [{path: '/list', search: listSearch}]},
89
+ createBrowserHistory(),
90
+ // Your resolveView consumes route.search itself: parse the location
91
+ // search, then resolve the view from the parsed output
92
+ async (matched, {location}) =>
93
+ renderList(await parseSearch(matched.at(-1)!.route.search!, location.search))
94
+ );
95
+ ```
96
+
97
+ - `parseSearchInput(search)` degrades a query string into a plain object — single-valued keys are strings, keys repeated in the query are arrays — which is also the input every schema validates
98
+ - `parseSearch(schema, search)` resolves the schema output (async validators are awaited); `parseSearchSync` is the render/guard-time flavor and rejects async validators with a clear error
99
+ - A rejected validation throws `SearchError` (a `NativeRouterError`) carrying the raw `search` and the reported `issues` — route it through your `errorHandler` like any other resolve failure
100
+
76
101
  ## Install
77
102
 
78
103
  ```bash
package/dist/index.cjs CHANGED
@@ -18,6 +18,33 @@ class RedirectLoopError extends NativeRouterError {
18
18
  }
19
19
  }
20
20
 
21
+ /**
22
+ * Thrown when a route {@link BaseRoute.search search schema} rejects the
23
+ * location search. Issues are formatted as `path: message` pairs joined
24
+ * with `; `, e.g.
25
+ * `Invalid search params "?page=abc": page: Expected a positive integer`.
26
+ */
27
+ class SearchError extends NativeRouterError {
28
+ /** The raw search string that failed validation. */
29
+ search;
30
+
31
+ /** The issues reported by the schema. */
32
+ issues;
33
+ constructor(search, issues) {
34
+ super(`Invalid search params "${search}": ${issues.map(({
35
+ message,
36
+ path
37
+ }) => `${formatIssuePath(path)}${message}`).join('; ')}`);
38
+ this.search = search;
39
+ this.issues = issues;
40
+ }
41
+ }
42
+ function formatIssuePath(path) {
43
+ if (!path?.length) return '';
44
+ const keys = path.map(segment => typeof segment === 'object' ? String(segment.key) : String(segment));
45
+ return `${keys.join('.')}: `;
46
+ }
47
+
21
48
  const DEFAULT_MAX_STACK_DEPTH = 100;
22
49
 
23
50
  /** Max redirects followed by {@link resolveEntry} before giving up. */
@@ -184,7 +211,7 @@ function match(router, pathname) {
184
211
  const route = routes[i];
185
212
  const end = !route.children;
186
213
  const matched = route.path ? pathToRegexp.match(route.path, {
187
- strict: true,
214
+ trailing: false,
188
215
  sensitive: true,
189
216
  decode: typeof decodeURIComponent === 'function' ? decodeURIComponent : undefined,
190
217
  end
@@ -753,9 +780,88 @@ function getParams(router) {
753
780
  return mergeMatchedParams(match(router, location.pathname) ?? []);
754
781
  }
755
782
 
783
+ /**
784
+ * Parse a raw search string(e.g. `?page=2&tag=a&tag=b`) into the plain
785
+ * input object consumed by {@link StandardSchemaV1 search schemas}:
786
+ * single-valued keys are strings, keys repeated in the query string are
787
+ * arrays of their values. An empty search is `{}`.
788
+ *
789
+ * This is also the degraded shape every search API falls back to when no
790
+ * schema is given.
791
+ * @group Methods
792
+ * @category Route
793
+ * @param search the raw `location.search` string, with or without `?`
794
+ * @returns the input object for schema validation
795
+ */
796
+ function parseSearchInput(search) {
797
+ const input = {};
798
+ // eslint-disable-next-line compat/compat -- URLSearchParams support is the app's polyfill concern, not bundled
799
+ new URLSearchParams(search).forEach((value, key) => {
800
+ const prev = input[key];
801
+ if (prev === undefined) {
802
+ input[key] = value;
803
+ } else if (Array.isArray(prev)) {
804
+ prev.push(value);
805
+ } else {
806
+ input[key] = [prev, value];
807
+ }
808
+ });
809
+ return input;
810
+ }
811
+
812
+ /**
813
+ * Validate a search string with a {@link StandardSchemaV1} schema — any
814
+ * zod/valibot/arktype schema works, no hard dependency. The string is
815
+ * first degraded via {@link parseSearchInput}, then parsed by the schema,
816
+ * so schemas can coerce(`'2'` → `2`) and normalize along the way.
817
+ *
818
+ * Async schemas(`validate` returning a promise) are awaited.
819
+ *
820
+ * @group Methods
821
+ * @category Route
822
+ * @param schema the search schema
823
+ * @param search the raw `location.search` string
824
+ * @returns the parsed(and possibly coerced) output of the schema
825
+ * @throws {SearchError} when the schema reports issues
826
+ */
827
+ async function parseSearch(schema, search) {
828
+ const result = await schema['~standard'].validate(parseSearchInput(search));
829
+ if (result.issues) throw new SearchError(search, result.issues);
830
+ // The schema's declared output; the loose `StandardSchemaV1` default
831
+ // degrades to `unknown`.
832
+ return result.value;
833
+ }
834
+
835
+ /**
836
+ * Synchronous flavor of {@link parseSearch}, for render-time reads(see
837
+ * `useSearch` of `@native-router/react`) and route guards.
838
+ *
839
+ * @group Methods
840
+ * @category Route
841
+ * @param schema the search schema — must validate synchronously
842
+ * @param search the raw `location.search` string
843
+ * @returns the parsed(and possibly coerced) output of the schema
844
+ * @throws {SearchError} when the schema reports issues
845
+ * @throws when the schema validates asynchronously; use {@link parseSearch}
846
+ * for async schemas instead
847
+ */
848
+ function parseSearchSync(schema, search) {
849
+ const result = schema['~standard'].validate(parseSearchInput(search));
850
+ if (isThenable(result)) {
851
+ throw new Error('The search schema validates asynchronously; parse it during resolve ' + '(parseSearch) instead of synchronously');
852
+ }
853
+ if (result.issues) throw new SearchError(search, result.issues);
854
+ // See parseSearch for the cast rationale.
855
+ return result.value;
856
+ }
857
+ function isThenable(value) {
858
+ return typeof value?.then === 'function';
859
+ }
860
+
756
861
  exports.NativeRouterError = NativeRouterError;
757
862
  exports.NotFoundError = NotFoundError;
758
863
  exports.RedirectLoopError = RedirectLoopError;
864
+ exports.SearchError = SearchError;
759
865
  exports.back = back;
760
866
  exports.cancel = cancel;
761
867
  exports.commit = commit;
@@ -772,6 +878,9 @@ exports.listen = listen;
772
878
  exports.match = match;
773
879
  exports.mergeMatchedParams = mergeMatchedParams;
774
880
  exports.navigate = navigate;
881
+ exports.parseSearch = parseSearch;
882
+ exports.parseSearchInput = parseSearchInput;
883
+ exports.parseSearchSync = parseSearchSync;
775
884
  exports.preload = preload;
776
885
  exports.refresh = refresh;
777
886
  exports.resolve = resolve;
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { parsePath, createPath } from 'history';
1
+ import { createPath, parsePath } from 'history';
2
2
  import { match as match$1 } from 'path-to-regexp';
3
- import { reject, noop, createCurrentGuard } from './util.mjs';
3
+ import { createCurrentGuard, reject, noop } from './util.mjs';
4
4
 
5
5
  /* eslint-disable max-classes-per-file */
6
6
 
@@ -16,6 +16,33 @@ class RedirectLoopError extends NativeRouterError {
16
16
  }
17
17
  }
18
18
 
19
+ /**
20
+ * Thrown when a route {@link BaseRoute.search search schema} rejects the
21
+ * location search. Issues are formatted as `path: message` pairs joined
22
+ * with `; `, e.g.
23
+ * `Invalid search params "?page=abc": page: Expected a positive integer`.
24
+ */
25
+ class SearchError extends NativeRouterError {
26
+ /** The raw search string that failed validation. */
27
+ search;
28
+
29
+ /** The issues reported by the schema. */
30
+ issues;
31
+ constructor(search, issues) {
32
+ super(`Invalid search params "${search}": ${issues.map(({
33
+ message,
34
+ path
35
+ }) => `${formatIssuePath(path)}${message}`).join('; ')}`);
36
+ this.search = search;
37
+ this.issues = issues;
38
+ }
39
+ }
40
+ function formatIssuePath(path) {
41
+ if (!path?.length) return '';
42
+ const keys = path.map(segment => typeof segment === 'object' ? String(segment.key) : String(segment));
43
+ return `${keys.join('.')}: `;
44
+ }
45
+
19
46
  const DEFAULT_MAX_STACK_DEPTH = 100;
20
47
 
21
48
  /** Max redirects followed by {@link resolveEntry} before giving up. */
@@ -182,7 +209,7 @@ function match(router, pathname) {
182
209
  const route = routes[i];
183
210
  const end = !route.children;
184
211
  const matched = route.path ? match$1(route.path, {
185
- strict: true,
212
+ trailing: false,
186
213
  sensitive: true,
187
214
  decode: typeof decodeURIComponent === 'function' ? decodeURIComponent : undefined,
188
215
  end
@@ -751,4 +778,82 @@ function getParams(router) {
751
778
  return mergeMatchedParams(match(router, location.pathname) ?? []);
752
779
  }
753
780
 
754
- export { NativeRouterError, NotFoundError, RedirectLoopError, back, cancel, commit, commitReplace, create, createHref, forward, getCurrentView, getLocation, getParams, go, initHistoryStack, listen, match, mergeMatchedParams, navigate, preload, refresh, resolve, resolveEntry, resolveTo, setOptions, toLocation };
781
+ /**
782
+ * Parse a raw search string(e.g. `?page=2&tag=a&tag=b`) into the plain
783
+ * input object consumed by {@link StandardSchemaV1 search schemas}:
784
+ * single-valued keys are strings, keys repeated in the query string are
785
+ * arrays of their values. An empty search is `{}`.
786
+ *
787
+ * This is also the degraded shape every search API falls back to when no
788
+ * schema is given.
789
+ * @group Methods
790
+ * @category Route
791
+ * @param search the raw `location.search` string, with or without `?`
792
+ * @returns the input object for schema validation
793
+ */
794
+ function parseSearchInput(search) {
795
+ const input = {};
796
+ // eslint-disable-next-line compat/compat -- URLSearchParams support is the app's polyfill concern, not bundled
797
+ new URLSearchParams(search).forEach((value, key) => {
798
+ const prev = input[key];
799
+ if (prev === undefined) {
800
+ input[key] = value;
801
+ } else if (Array.isArray(prev)) {
802
+ prev.push(value);
803
+ } else {
804
+ input[key] = [prev, value];
805
+ }
806
+ });
807
+ return input;
808
+ }
809
+
810
+ /**
811
+ * Validate a search string with a {@link StandardSchemaV1} schema — any
812
+ * zod/valibot/arktype schema works, no hard dependency. The string is
813
+ * first degraded via {@link parseSearchInput}, then parsed by the schema,
814
+ * so schemas can coerce(`'2'` → `2`) and normalize along the way.
815
+ *
816
+ * Async schemas(`validate` returning a promise) are awaited.
817
+ *
818
+ * @group Methods
819
+ * @category Route
820
+ * @param schema the search schema
821
+ * @param search the raw `location.search` string
822
+ * @returns the parsed(and possibly coerced) output of the schema
823
+ * @throws {SearchError} when the schema reports issues
824
+ */
825
+ async function parseSearch(schema, search) {
826
+ const result = await schema['~standard'].validate(parseSearchInput(search));
827
+ if (result.issues) throw new SearchError(search, result.issues);
828
+ // The schema's declared output; the loose `StandardSchemaV1` default
829
+ // degrades to `unknown`.
830
+ return result.value;
831
+ }
832
+
833
+ /**
834
+ * Synchronous flavor of {@link parseSearch}, for render-time reads(see
835
+ * `useSearch` of `@native-router/react`) and route guards.
836
+ *
837
+ * @group Methods
838
+ * @category Route
839
+ * @param schema the search schema — must validate synchronously
840
+ * @param search the raw `location.search` string
841
+ * @returns the parsed(and possibly coerced) output of the schema
842
+ * @throws {SearchError} when the schema reports issues
843
+ * @throws when the schema validates asynchronously; use {@link parseSearch}
844
+ * for async schemas instead
845
+ */
846
+ function parseSearchSync(schema, search) {
847
+ const result = schema['~standard'].validate(parseSearchInput(search));
848
+ if (isThenable(result)) {
849
+ throw new Error('The search schema validates asynchronously; parse it during resolve ' + '(parseSearch) instead of synchronously');
850
+ }
851
+ if (result.issues) throw new SearchError(search, result.issues);
852
+ // See parseSearch for the cast rationale.
853
+ return result.value;
854
+ }
855
+ function isThenable(value) {
856
+ return typeof value?.then === 'function';
857
+ }
858
+
859
+ export { NativeRouterError, NotFoundError, RedirectLoopError, SearchError, back, cancel, commit, commitReplace, create, createHref, forward, getCurrentView, getLocation, getParams, go, initHistoryStack, listen, match, mergeMatchedParams, navigate, parseSearch, parseSearchInput, parseSearchSync, preload, refresh, resolve, resolveEntry, resolveTo, setOptions, toLocation };
@@ -1,3 +1,4 @@
1
+ import type { StandardSchemaV1 } from './types';
1
2
  export declare class NativeRouterError extends Error {
2
3
  }
3
4
  export declare class NotFoundError extends NativeRouterError {
@@ -6,3 +7,16 @@ export declare class NotFoundError extends NativeRouterError {
6
7
  export declare class RedirectLoopError extends NativeRouterError {
7
8
  constructor(target?: string);
8
9
  }
10
+ /**
11
+ * Thrown when a route {@link BaseRoute.search search schema} rejects the
12
+ * location search. Issues are formatted as `path: message` pairs joined
13
+ * with `; `, e.g.
14
+ * `Invalid search params "?page=abc": page: Expected a positive integer`.
15
+ */
16
+ export declare class SearchError extends NativeRouterError {
17
+ /** The raw search string that failed validation. */
18
+ readonly search: string;
19
+ /** The issues reported by the schema. */
20
+ readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
21
+ constructor(search: string, issues: ReadonlyArray<StandardSchemaV1.Issue>);
22
+ }
@@ -1,3 +1,4 @@
1
1
  export * from './router';
2
2
  export * from './errors';
3
+ export * from './search';
3
4
  export type * from './types';
@@ -0,0 +1,45 @@
1
+ import type { SearchInput, SearchOutputOf, StandardSchemaV1 } from './types';
2
+ /**
3
+ * Parse a raw search string(e.g. `?page=2&tag=a&tag=b`) into the plain
4
+ * input object consumed by {@link StandardSchemaV1 search schemas}:
5
+ * single-valued keys are strings, keys repeated in the query string are
6
+ * arrays of their values. An empty search is `{}`.
7
+ *
8
+ * This is also the degraded shape every search API falls back to when no
9
+ * schema is given.
10
+ * @group Methods
11
+ * @category Route
12
+ * @param search the raw `location.search` string, with or without `?`
13
+ * @returns the input object for schema validation
14
+ */
15
+ export declare function parseSearchInput(search: string): SearchInput;
16
+ /**
17
+ * Validate a search string with a {@link StandardSchemaV1} schema — any
18
+ * zod/valibot/arktype schema works, no hard dependency. The string is
19
+ * first degraded via {@link parseSearchInput}, then parsed by the schema,
20
+ * so schemas can coerce(`'2'` → `2`) and normalize along the way.
21
+ *
22
+ * Async schemas(`validate` returning a promise) are awaited.
23
+ *
24
+ * @group Methods
25
+ * @category Route
26
+ * @param schema the search schema
27
+ * @param search the raw `location.search` string
28
+ * @returns the parsed(and possibly coerced) output of the schema
29
+ * @throws {SearchError} when the schema reports issues
30
+ */
31
+ export declare function parseSearch<S extends StandardSchemaV1>(schema: S, search: string): Promise<SearchOutputOf<S>>;
32
+ /**
33
+ * Synchronous flavor of {@link parseSearch}, for render-time reads(see
34
+ * `useSearch` of `@native-router/react`) and route guards.
35
+ *
36
+ * @group Methods
37
+ * @category Route
38
+ * @param schema the search schema — must validate synchronously
39
+ * @param search the raw `location.search` string
40
+ * @returns the parsed(and possibly coerced) output of the schema
41
+ * @throws {SearchError} when the schema reports issues
42
+ * @throws when the schema validates asynchronously; use {@link parseSearch}
43
+ * for async schemas instead
44
+ */
45
+ export declare function parseSearchSync<S extends StandardSchemaV1>(schema: S, search: string): SearchOutputOf<S>;
@@ -22,6 +22,63 @@ export type HistoryState = {
22
22
  };
23
23
  export type WrappedLocation = Location<HistoryState>;
24
24
  export type Awaitable<T> = T | Promise<T>;
25
+ /**
26
+ * The [Standard Schema](https://standardschema.dev) interface, version 1 —
27
+ * the common validation interface implemented by zod, valibot and arktype.
28
+ *
29
+ * Inlined type-only from `@standard-schema/spec` so the core keeps zero
30
+ * extra runtime dependencies: any schema exposing `~standard` works.
31
+ * @group Types
32
+ * @category Route
33
+ */
34
+ export interface StandardSchemaV1<Input = unknown, Output = Input> {
35
+ readonly '~standard': StandardSchemaV1.Props<Input, Output>;
36
+ }
37
+ export declare namespace StandardSchemaV1 {
38
+ interface Props<Input = unknown, Output = Input> {
39
+ /** The version number of the standard. */
40
+ readonly version: 1;
41
+ /** The vendor name of the schema library. */
42
+ readonly vendor: string;
43
+ /** Validates unknown input values. */
44
+ readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
45
+ }
46
+ type Result<Output> = SuccessResult<Output> | FailureResult;
47
+ interface SuccessResult<Output> {
48
+ /** The typed output value. */
49
+ readonly value: Output;
50
+ /** The issues of the input value. */
51
+ readonly issues?: undefined;
52
+ }
53
+ interface FailureResult {
54
+ /** The issues of the input value. */
55
+ readonly issues: ReadonlyArray<Issue>;
56
+ }
57
+ interface Issue {
58
+ /** The issue message. */
59
+ readonly message: string;
60
+ /** The issue path. */
61
+ readonly path?: ReadonlyArray<PropertyKey | PathSegment>;
62
+ }
63
+ interface PathSegment {
64
+ /** The key of the path segment. */
65
+ readonly key: PropertyKey;
66
+ }
67
+ }
68
+ /**
69
+ * The plain input object a search string degrades into before schema
70
+ * validation: single-valued keys are strings, keys repeated in the query
71
+ * string are arrays of their values.
72
+ * @group Types
73
+ * @category Route
74
+ */
75
+ export type SearchInput = Record<string, string | string[]>;
76
+ /**
77
+ * Parsed output type of a {@link StandardSchemaV1 search schema}.
78
+ * @group Types
79
+ * @category Route
80
+ */
81
+ export type SearchOutputOf<S> = S extends StandardSchemaV1<any, infer Output> ? Output : never;
25
82
  /**
26
83
  * Params contributed by a single path segment: `:name` is required,
27
84
  * `:name?` is optional, anything else(static or wildcard) contributes
@@ -70,6 +127,14 @@ export type BaseRoute<T = any> = {
70
127
  * redirected to the target path before the view resolves.
71
128
  */
72
129
  redirect?: string;
130
+ /**
131
+ * Optional Standard Schema(zod/valibot/arktype, ...) validator of the
132
+ * route search. Frameworks parse `location.search` with it at resolve
133
+ * time(see `parseSearch`) and inject the parsed output into their data
134
+ * contexts; a validation failure fails the resolve like any other
135
+ * navigation error.
136
+ */
137
+ search?: StandardSchemaV1;
73
138
  /**
74
139
  * Route guard invoked before the view resolves. Return a path string
75
140
  * to redirect, or nothing(`undefined`) to continue.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@native-router/core",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "exports": {
5
5
  ".": {
6
6
  "types": "./dist/types/index.d.ts",
@@ -52,24 +52,24 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "history": "^5.3.0",
55
- "path-to-regexp": "^6.2.1"
55
+ "path-to-regexp": "^8.4.2"
56
56
  },
57
57
  "devDependencies": {
58
- "@babel/core": "^7.22.9",
59
- "@babel/preset-env": "^7.22.9",
60
- "@babel/preset-typescript": "^7.22.5",
61
- "@rollup/plugin-babel": "^6.0.3",
62
- "@rollup/plugin-commonjs": "^25.0.4",
63
- "@rollup/plugin-node-resolve": "^15.1.0",
64
- "@rollup/plugin-replace": "^5.0.2",
65
- "@types/node": "^20.4.5",
66
- "@types/sinon": "^10.0.15",
58
+ "@babel/core": "^8.0.1",
59
+ "@babel/preset-env": "^8.0.2",
60
+ "@babel/preset-typescript": "^8.0.1",
61
+ "@rollup/plugin-babel": "^7.1.0",
62
+ "@rollup/plugin-commonjs": "^29.0.3",
63
+ "@rollup/plugin-node-resolve": "^16.0.3",
64
+ "@rollup/plugin-replace": "^6.0.3",
65
+ "@types/node": "^26.2.0",
66
+ "@types/sinon": "^22.0.0",
67
67
  "@typescript-eslint/eslint-plugin": "^6.2.0",
68
68
  "@typescript-eslint/parser": "^6.2.0",
69
- "@vitest/coverage-v8": "^4.0.18",
70
- "commitizen": "^4.3.0",
71
- "core-js": "^3.31.1",
72
- "cross-env": "^7.0.3",
69
+ "@vitest/coverage-v8": "^4.1.11",
70
+ "commitizen": "^4.3.2",
71
+ "core-js": "^3.50.0",
72
+ "cross-env": "^10.1.0",
73
73
  "eslint": "^8.50.0",
74
74
  "eslint-config-airbnb": "^19.0.4",
75
75
  "eslint-config-airbnb-typescript": "^17.1.0",
@@ -81,21 +81,21 @@
81
81
  "eslint-plugin-prettier": "^5.0.0",
82
82
  "eslint-plugin-react": "^7.33.0",
83
83
  "eslint-plugin-react-hooks": "^4.6.0",
84
- "gh-pages": "^5.0.0",
85
- "husky": "^8.0.3",
86
- "lint-staged": "^13.2.3",
87
- "prettier": "^3.0.0",
88
- "rollup": "^3.28.0",
84
+ "gh-pages": "^6.3.0",
85
+ "husky": "^9.1.7",
86
+ "lint-staged": "^17.3.0",
87
+ "prettier": "^3.9.6",
88
+ "rollup": "^4.62.5",
89
+ "semantic-release": "^25.0.9",
89
90
  "should": "^13.2.3",
90
91
  "should-sinon": "0.0.6",
91
- "sinon": "^15.2.0",
92
- "terser": "^5.19.2",
93
- "tsc-alias": "^1.8.7",
94
- "typedoc": "^0.24.8",
92
+ "sinon": "^22.1.0",
93
+ "terser": "^5.50.0",
94
+ "tsc-alias": "^1.9.2",
95
+ "typedoc": "^0.28.20",
95
96
  "typedoc-plugin-mark-react-functional-components": "^0.2.2",
96
- "typedoc-plugin-missing-exports": "^2.0.0",
97
- "typescript": "^5.9.3",
98
- "vitest": "^4.0.18",
99
- "semantic-release": "^25.0.3"
97
+ "typedoc-plugin-missing-exports": "^4.1.4",
98
+ "typescript": "~5.9.3",
99
+ "vitest": "^4.1.11"
100
100
  }
101
101
  }