@ereo/client 0.1.6

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.
@@ -0,0 +1,238 @@
1
+ /**
2
+ * @ereo/client - Type-Safe Navigation Utilities
3
+ *
4
+ * Navigate and redirect functions with compile-time route validation.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * // Client-side navigation
9
+ * await typedNavigate('/users/[id]', { params: { id: '123' } });
10
+ *
11
+ * // Server-side redirect
12
+ * return typedRedirect('/login', { search: { returnTo: '/dashboard' } });
13
+ *
14
+ * // With search and hash params (Ereo exclusive)
15
+ * await typedNavigate('/posts/[slug]', {
16
+ * params: { slug: 'hello' },
17
+ * search: { page: 1 },
18
+ * hash: { section: 'comments' },
19
+ * });
20
+ * ```
21
+ */
22
+ import type { TypedRoutes, RouteParamsFor, SearchParamsFor, HashParamsFor } from '@ereo/core';
23
+ /**
24
+ * Check if params object is empty (no required params).
25
+ */
26
+ type IsEmptyObject<T> = keyof T extends never ? true : false;
27
+ /**
28
+ * Check if all properties in T are optional.
29
+ */
30
+ type AllOptional<T> = {
31
+ [K in keyof T]-?: {} extends Pick<T, K> ? true : false;
32
+ }[keyof T] extends true ? true : false;
33
+ /**
34
+ * Navigation options with conditional params requirement.
35
+ */
36
+ export type TypedNavigateOptions<Path extends TypedRoutes> = (IsEmptyObject<RouteParamsFor<Path>> extends true ? {
37
+ params?: never;
38
+ } : AllOptional<RouteParamsFor<Path>> extends true ? {
39
+ params?: RouteParamsFor<Path>;
40
+ } : {
41
+ params: RouteParamsFor<Path>;
42
+ }) & {
43
+ /** Search params */
44
+ search?: Partial<SearchParamsFor<Path>>;
45
+ /** Hash params - unique to Ereo */
46
+ hash?: Partial<HashParamsFor<Path>>;
47
+ /** Replace history instead of push */
48
+ replace?: boolean;
49
+ /** State to pass to the location */
50
+ state?: unknown;
51
+ /** Scroll to top after navigation */
52
+ scroll?: boolean;
53
+ };
54
+ /**
55
+ * Redirect options with conditional params requirement.
56
+ */
57
+ export type TypedRedirectOptions<Path extends TypedRoutes> = (IsEmptyObject<RouteParamsFor<Path>> extends true ? {
58
+ params?: never;
59
+ } : AllOptional<RouteParamsFor<Path>> extends true ? {
60
+ params?: RouteParamsFor<Path>;
61
+ } : {
62
+ params: RouteParamsFor<Path>;
63
+ }) & {
64
+ /** Search params */
65
+ search?: Partial<SearchParamsFor<Path>>;
66
+ /** Hash params - unique to Ereo */
67
+ hash?: Partial<HashParamsFor<Path>>;
68
+ /** HTTP status code (default: 302) */
69
+ status?: 301 | 302 | 303 | 307 | 308;
70
+ /** Custom headers */
71
+ headers?: HeadersInit;
72
+ };
73
+ /**
74
+ * Build a complete URL from pattern, params, search, and hash.
75
+ */
76
+ export declare function buildTypedUrl<Path extends TypedRoutes>(pattern: Path, options?: {
77
+ params?: RouteParamsFor<Path>;
78
+ search?: Partial<SearchParamsFor<Path>>;
79
+ hash?: Partial<HashParamsFor<Path>>;
80
+ }): string;
81
+ /**
82
+ * Type-safe client-side navigation.
83
+ *
84
+ * Validates that:
85
+ * 1. The route path exists in your route definitions
86
+ * 2. Required params are provided with correct types
87
+ * 3. Search params match the route's search schema
88
+ * 4. Hash params match the route's hash schema (Ereo exclusive)
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * // Navigate to a static route
93
+ * await typedNavigate('/about');
94
+ *
95
+ * // Navigate with params
96
+ * await typedNavigate('/users/[id]', { params: { id: '123' } });
97
+ *
98
+ * // Navigate with all options
99
+ * await typedNavigate('/posts/[slug]', {
100
+ * params: { slug: 'hello-world' },
101
+ * search: { page: 1, sort: 'asc' },
102
+ * hash: { section: 'comments' },
103
+ * replace: true,
104
+ * state: { fromDashboard: true },
105
+ * });
106
+ *
107
+ * // Error - missing required params
108
+ * await typedNavigate('/users/[id]'); // TypeScript error!
109
+ * ```
110
+ */
111
+ export declare function typedNavigate<Path extends TypedRoutes>(path: Path, options?: TypedNavigateOptions<Path>): Promise<void>;
112
+ /**
113
+ * Type-safe navigation function returned by useTypedNavigate.
114
+ */
115
+ export interface TypedNavigateFunction {
116
+ /**
117
+ * Navigate to a typed route.
118
+ */
119
+ <Path extends TypedRoutes>(path: Path, options?: TypedNavigateOptions<Path>): Promise<void>;
120
+ /**
121
+ * Navigate by delta (back/forward).
122
+ */
123
+ (delta: number): void;
124
+ }
125
+ /**
126
+ * Hook that returns a type-safe navigate function.
127
+ *
128
+ * @example
129
+ * ```tsx
130
+ * function MyComponent() {
131
+ * const navigate = useTypedNavigate();
132
+ *
133
+ * const handleClick = () => {
134
+ * navigate('/users/[id]', { params: { id: '123' } });
135
+ * };
136
+ *
137
+ * const handleBack = () => {
138
+ * navigate(-1);
139
+ * };
140
+ *
141
+ * return <button onClick={handleClick}>Go to user</button>;
142
+ * }
143
+ * ```
144
+ */
145
+ export declare function useTypedNavigate(): TypedNavigateFunction;
146
+ /**
147
+ * Type-safe server-side redirect.
148
+ *
149
+ * Creates a Response with redirect status and Location header.
150
+ * Use this in loaders and actions for server-side redirects.
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * // In a loader or action
155
+ * export const loader = async ({ request, context }) => {
156
+ * const user = context.get<User>('user');
157
+ *
158
+ * if (!user) {
159
+ * return typedRedirect('/login', {
160
+ * search: { returnTo: new URL(request.url).pathname },
161
+ * });
162
+ * }
163
+ *
164
+ * return { user };
165
+ * };
166
+ *
167
+ * // Redirect to a route with params
168
+ * return typedRedirect('/users/[id]', {
169
+ * params: { id: user.id },
170
+ * status: 303,
171
+ * });
172
+ * ```
173
+ */
174
+ export declare function typedRedirect<Path extends TypedRoutes>(path: Path, options?: TypedRedirectOptions<Path>): Response;
175
+ /**
176
+ * Alias for typedRedirect for familiarity.
177
+ */
178
+ export declare const redirect: typeof typedRedirect;
179
+ /**
180
+ * Parse search params from a URL using a route's schema.
181
+ * Returns typed search params for the given route.
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * const url = new URL(request.url);
186
+ * const searchParams = parseTypedSearchParams<'/posts'>(url);
187
+ * // searchParams is typed as SearchParamsFor<'/posts'>
188
+ * ```
189
+ */
190
+ export declare function parseTypedSearchParams<Path extends TypedRoutes>(url: URL | string): Partial<SearchParamsFor<Path>>;
191
+ /**
192
+ * Parse hash params from a URL using a route's schema.
193
+ * Returns typed hash params for the given route.
194
+ * This is UNIQUE to Ereo - TanStack has no hash param support.
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * const url = new URL(request.url);
199
+ * const hashParams = parseTypedHashParams<'/posts/[slug]'>(url);
200
+ * // hashParams is typed as HashParamsFor<'/posts/[slug]'>
201
+ * ```
202
+ */
203
+ export declare function parseTypedHashParams<Path extends TypedRoutes>(url: URL | string): Partial<HashParamsFor<Path>>;
204
+ /**
205
+ * Go back in history.
206
+ */
207
+ export declare function goBack(): void;
208
+ /**
209
+ * Go forward in history.
210
+ */
211
+ export declare function goForward(): void;
212
+ /**
213
+ * Go to a specific history entry.
214
+ */
215
+ export declare function go(delta: number): void;
216
+ /**
217
+ * Check if a path is the current location.
218
+ */
219
+ export declare function isCurrentPath<Path extends TypedRoutes>(path: Path, options?: {
220
+ params?: RouteParamsFor<Path>;
221
+ exact?: boolean;
222
+ }): boolean;
223
+ /**
224
+ * Preload a route's data before navigation.
225
+ * Useful for preparing data in advance.
226
+ *
227
+ * @example
228
+ * ```typescript
229
+ * // Preload on hover
230
+ * onMouseEnter={() => preloadRoute('/users/[id]', { params: { id: '123' } })}
231
+ * ```
232
+ */
233
+ export declare function preloadRoute<Path extends TypedRoutes>(path: Path, options?: {
234
+ params?: RouteParamsFor<Path>;
235
+ search?: Partial<SearchParamsFor<Path>>;
236
+ }): Promise<void>;
237
+ export type { TypedRoutes, RouteParamsFor, SearchParamsFor, HashParamsFor };
238
+ //# sourceMappingURL=typed-navigate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-navigate.d.ts","sourceRoot":"","sources":["../src/typed-navigate.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@ereo/client",
3
+ "version": "0.1.6",
4
+ "license": "MIT",
5
+ "author": "Ereo Team",
6
+ "homepage": "https://ereo.dev",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/ereojs/ereo.git",
10
+ "directory": "packages/client"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/ereojs/ereo/issues"
14
+ },
15
+ "type": "module",
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "scripts": {
28
+ "build": "bun build ./src/index.ts --outdir ./dist --target browser --external @ereo/core --external react --external react-dom && bun run build:types",
29
+ "build:types": "tsc --emitDeclarationOnly --outDir dist",
30
+ "dev": "bun build ./src/index.ts --outdir ./dist --target browser --watch",
31
+ "test": "bun test",
32
+ "typecheck": "tsc --noEmit"
33
+ },
34
+ "dependencies": {
35
+ "@ereo/core": "workspace:*"
36
+ },
37
+ "devDependencies": {
38
+ "@types/react": "^18.2.0",
39
+ "@types/react-dom": "^18.2.0",
40
+ "typescript": "^5.4.0"
41
+ },
42
+ "peerDependencies": {
43
+ "react": "^18.0.0",
44
+ "react-dom": "^18.0.0"
45
+ }
46
+ }