@bb-labs/next-router 0.0.2 → 0.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/README.md CHANGED
@@ -35,9 +35,9 @@ import { z } from "zod";
35
35
 
36
36
  export default zPage({
37
37
  params: {
38
- searchParams: z.object({
38
+ searchParams: {
39
39
  email: z.string().email(),
40
- }),
40
+ },
41
41
  },
42
42
  handler: ({ searchParams }) => {
43
43
  // Already awaited — use directly
@@ -56,17 +56,18 @@ export default zPage({
56
56
  When `resolve: false`, params are passed as **promises** — you control when to await.
57
57
 
58
58
  ```tsx
59
- import { zPage, resolveParams } from "@bb-labs/next-router";
59
+ import { zPage } from "@bb-labs/next-router";
60
+ import { resolveZPageParams } from "@bb-labs/next-router/common";
60
61
  import { z } from "zod";
61
62
 
62
63
  export default zPage({
63
64
  params: {
64
- routeParams: z.object({ id: z.string() }),
65
- searchParams: z.object({ page: z.coerce.number().optional() }),
65
+ routeParams: { id: z.string() },
66
+ searchParams: { page: z.coerce.number().optional() },
66
67
  },
67
68
  resolve: false,
68
69
  handler: async (paramsPromise) => {
69
- const { routeParams, searchParams } = await resolveParams(paramsPromise);
70
+ const { routeParams, searchParams } = await resolveZPageParams(paramsPromise);
70
71
  return (
71
72
  <div>
72
73
  Product {routeParams.id}, Page {searchParams.page}
@@ -78,24 +79,25 @@ export default zPage({
78
79
 
79
80
  **Note:** `onError` and `loadingHandler` are not available when `resolve: false`.
80
81
 
81
- ### `resolveParams`
82
+ ### `resolveZPageParams`
82
83
 
83
84
  Helper function to await and validate params from promise-based handlers. Optionally accepts an `onError` callback.
84
85
 
85
86
  ```tsx
86
- import { zPage, resolveParams } from "@bb-labs/next-router";
87
+ import { zPage } from "@bb-labs/next-router";
88
+ import { resolveZPageParams } from "@bb-labs/next-router/common";
87
89
  import { redirect } from "next/navigation";
88
90
  import { z } from "zod";
89
91
 
90
92
  export default zPage({
91
93
  params: {
92
- searchParams: z.object({
94
+ searchParams: {
93
95
  email: z.string().email(),
94
- }),
96
+ },
95
97
  },
96
98
  resolve: false,
97
99
  handler: async (paramsPromise) => {
98
- const { searchParams } = await resolveParams(paramsPromise, {
100
+ const { searchParams } = await resolveZPageParams(paramsPromise, {
99
101
  onError: (error) => {
100
102
  console.error("Validation failed:", error);
101
103
  redirect("/custom-error");
@@ -112,13 +114,13 @@ You can provide both, only `routeParams`, or only `searchParams` — but never n
112
114
 
113
115
  ```tsx
114
116
  // ✅ Both
115
- { params: { routeParams: z.object({...}), searchParams: z.object({...}) } }
117
+ { params: { routeParams: {...}, searchParams: {...} } }
116
118
 
117
119
  // ✅ Only routeParams
118
- { params: { routeParams: z.object({...}) } }
120
+ { params: { routeParams: {...} } }
119
121
 
120
122
  // ✅ Only searchParams
121
- { params: { searchParams: z.object({...}) } }
123
+ { params: { searchParams: {...} } }
122
124
 
123
125
  // ❌ Neither — TypeScript error
124
126
  { params: {} }
@@ -138,9 +140,9 @@ Hooks for accessing validated params in client components with `onSuccess` and `
138
140
  import { useSearchParams } from "@bb-labs/next-router/client";
139
141
  import { z } from "zod";
140
142
 
141
- const searchParamsSchema = z.object({
143
+ const searchParamsSchema = {
142
144
  email: z.string().email(),
143
- });
145
+ };
144
146
 
145
147
  export function MyComponent() {
146
148
  const { data } = useSearchParams(searchParamsSchema, {
@@ -183,28 +185,28 @@ const { data } = useSearchParams(schema, options?);
183
185
 
184
186
  ```tsx
185
187
  // ✅ Correct — use coercion for non-string types
186
- z.object({
187
- id: z.string(), // strings work directly
188
- page: z.coerce.number(), // coerce string → number
189
- active: z.coerce.boolean(), // coerce string → boolean
190
- count: z.coerce.number().optional(), // optional coerced number
191
- tags: z.array(z.string()), // array of strings (for ?tags=a&tags=b)
192
- });
188
+ {
189
+ id: z.string(), // strings work directly
190
+ page: z.coerce.number(), // coerce string → number
191
+ active: z.coerce.boolean(), // coerce string → boolean
192
+ count: z.coerce.number().optional(), // optional coerced number
193
+ tags: z.array(z.string()), // array of strings (for ?tags=a&tags=b)
194
+ }
193
195
 
194
196
  // ❌ Wrong — will fail because raw input is always a string
195
- z.object({
196
- page: z.number(), // Error: expected number, received string
197
+ {
198
+ page: z.number(), // Error: expected number, received string
197
199
  active: z.boolean(), // Error: expected boolean, received string
198
- });
200
+ }
199
201
  ```
200
202
 
201
203
  You can also use transforms for custom parsing:
202
204
 
203
205
  ```tsx
204
- z.object({
206
+ {
205
207
  date: z.string().transform((s) => new Date(s)),
206
208
  ids: z.string().transform((s) => s.split(",")),
207
- });
209
+ }
208
210
  ```
209
211
 
210
212
  ### JSON-Encoded Objects
@@ -215,7 +217,7 @@ For complex objects, encode them as JSON in the URL (URL-escaped). Use `.transfo
215
217
  // URL: ?filter={"category":"books","price":{"min":10,"max":50},"inStock":true}
216
218
  // (URL-encoded: ?filter=%7B%22category%22%3A%22books%22...%7D)
217
219
 
218
- z.object({
220
+ {
219
221
  filter: z
220
222
  .string()
221
223
  .transform((s) => JSON.parse(s))
@@ -227,7 +229,7 @@ z.object({
227
229
  inStock: z.boolean(),
228
230
  })
229
231
  ),
230
- });
232
+ }
231
233
  ```
232
234
 
233
235
  **How it works:**
@@ -241,7 +243,7 @@ z.object({
241
243
  ```tsx
242
244
  export default zPage({
243
245
  params: {
244
- searchParams: z.object({
246
+ searchParams: {
245
247
  filter: z
246
248
  .string()
247
249
  .transform((s) => JSON.parse(s))
@@ -251,7 +253,7 @@ export default zPage({
251
253
  price: z.object({ min: z.number(), max: z.number() }),
252
254
  })
253
255
  ),
254
- }),
256
+ },
255
257
  },
256
258
  handler: ({ searchParams }) => {
257
259
  // searchParams.filter is fully typed!
@@ -278,7 +280,7 @@ const url = `/products?filter=${encodeURIComponent(JSON.stringify(filter))}`;
278
280
 
279
281
  By default, validation errors redirect to "/404":
280
282
 
281
- - **Server components**: `zPage` and `resolveParams` with `resolve: true` redirects on validation failure
283
+ - **Server components**: `zPage` and `resolveZPageParams` with `resolve: true` redirects on validation failure
282
284
  - **Client components**: `useRouteParams` and `useSearchParams` redirect on validation failure
283
285
 
284
286
  You can customize error handling:
@@ -286,6 +288,65 @@ You can customize error handling:
286
288
  - **Server**: Provide an `onError` callback to `zPage` (only available when `resolve: true`)
287
289
  - **Client**: Provide an `onError` callback to the hooks
288
290
 
291
+ ---
292
+
293
+ ## Type Utilities
294
+
295
+ The package exports type utilities from `@bb-labs/next-router/common` to help with type inference in advanced scenarios.
296
+
297
+ ### `InferZPageParams` / `InferZPageParamsPromises`
298
+
299
+ Infer the resolved param types from a `zPage` configuration. Useful when you need to pass params to child components.
300
+
301
+ ```tsx
302
+ import { zPage } from "@bb-labs/next-router";
303
+ import type { InferZPageParams, InferZPageParamsPromises } from "@bb-labs/next-router/common";
304
+ import { z } from "zod";
305
+
306
+ const pageParams = {
307
+ routeParams: { id: z.string() },
308
+ searchParams: { page: z.coerce.number() },
309
+ };
310
+
311
+ // Infer the resolved param types
312
+ type PageParams = InferZPageParams<typeof pageParams>;
313
+ // { routeParams: { id: string }, searchParams: { page: number } }
314
+
315
+ // For promise-wrapped params (when resolve: false)
316
+ type PageParamsPromises = InferZPageParamsPromises<typeof pageParams>;
317
+ // { routeParams: Promise<{ id: string }>, searchParams: Promise<{ page: number }> }
318
+
319
+ // Use in child components
320
+ function ProductDetails({ routeParams, searchParams }: PageParams) {
321
+ return (
322
+ <div>
323
+ Product {routeParams.id}, Page {searchParams.page}
324
+ </div>
325
+ );
326
+ }
327
+
328
+ export default zPage({
329
+ params: pageParams,
330
+ handler: (params) => <ProductDetails {...params} />,
331
+ });
332
+ ```
333
+
334
+ ### Flexible Schema Input
335
+
336
+ Both server and client APIs accept schemas in two formats:
337
+
338
+ ```tsx
339
+ // Format 1: z.object() directly
340
+ z.object({ id: z.string() });
341
+
342
+ // Format 2: Plain object shape (automatically wrapped) — recommended
343
+ {
344
+ id: z.string();
345
+ }
346
+ ```
347
+
348
+ Both formats are fully type-safe and produce the same runtime behavior.
349
+
289
350
  ## License
290
351
 
291
352
  MIT
@@ -1,13 +1,13 @@
1
- import { z, type ZodRawShape } from "zod";
2
- type ZodObject = z.ZodObject<ZodRawShape>;
1
+ import type { InferZodObjectShapeOutput, ZodObjectShape } from "../../utils/types";
2
+ import type { OnZodError } from "../../server/z-page/utils/types";
3
3
  type HookOptions<T> = {
4
4
  onSuccess?: (data: T) => void;
5
- onError?: (error: Error) => void;
5
+ onError?: OnZodError;
6
6
  };
7
- export declare function useRouteParams<T extends ZodObject>(schema: T, options?: HookOptions<z.output<T>>): {
8
- data: z.core.output<T> | null;
7
+ export declare function useRouteParams<T extends ZodObjectShape>(schema: T, options?: HookOptions<InferZodObjectShapeOutput<T>>): {
8
+ data: InferZodObjectShapeOutput<T> | null;
9
9
  };
10
- export declare function useSearchParams<T extends ZodObject>(schema: T, options?: HookOptions<z.output<T>>): {
11
- data: z.core.output<T> | null;
10
+ export declare function useSearchParams<T extends ZodObjectShape>(schema: T, options?: HookOptions<InferZodObjectShapeOutput<T>>): {
11
+ data: InferZodObjectShapeOutput<T> | null;
12
12
  };
13
13
  export {};
@@ -1,21 +1,26 @@
1
1
  "use client";
2
2
  import { useEffect, useRef, useMemo } from "react";
3
3
  import { useParams, useSearchParams as useNextSearchParams, useRouter } from "next/navigation";
4
+ import { toZodObject } from "../../utils/to-zod-object";
5
+ const defaultOnError = (error, router) => {
6
+ console.log(error);
7
+ router.push("/404");
8
+ };
4
9
  export function useRouteParams(schema, options) {
5
10
  const rawParams = useParams();
6
11
  const router = useRouter();
7
12
  const calledRef = useRef(false);
13
+ const zodSchema = useMemo(() => toZodObject(schema), [schema]);
8
14
  const result = useMemo(() => {
9
- const parsed = schema.safeParse(rawParams);
15
+ const parsed = zodSchema.safeParse(rawParams);
10
16
  return parsed.success ? { data: parsed.data, error: null } : { data: null, error: parsed.error };
11
- }, [rawParams, schema]);
17
+ }, [rawParams, zodSchema]);
12
18
  useEffect(() => {
13
19
  if (calledRef.current)
14
20
  return;
15
21
  calledRef.current = true;
16
22
  if (result.error) {
17
- console.log(result.error);
18
- options?.onError ? options.onError(result.error) : router.push("/404");
23
+ options?.onError ? options.onError(result.error) : defaultOnError(result.error, router);
19
24
  }
20
25
  else if (result.data) {
21
26
  options?.onSuccess?.(result.data);
@@ -27,22 +32,22 @@ export function useSearchParams(schema, options) {
27
32
  const nextSearchParams = useNextSearchParams();
28
33
  const router = useRouter();
29
34
  const calledRef = useRef(false);
35
+ const zodSchema = useMemo(() => toZodObject(schema), [schema]);
30
36
  const result = useMemo(() => {
31
37
  const raw = {};
32
38
  nextSearchParams.forEach((v, k) => {
33
39
  const existing = raw[k];
34
40
  raw[k] = existing ? (Array.isArray(existing) ? [...existing, v] : [existing, v]) : v;
35
41
  });
36
- const parsed = schema.safeParse(raw);
42
+ const parsed = zodSchema.safeParse(raw);
37
43
  return parsed.success ? { data: parsed.data, error: null } : { data: null, error: parsed.error };
38
- }, [nextSearchParams, schema]);
44
+ }, [nextSearchParams, zodSchema]);
39
45
  useEffect(() => {
40
46
  if (calledRef.current)
41
47
  return;
42
48
  calledRef.current = true;
43
49
  if (result.error) {
44
- console.log(result.error);
45
- options?.onError ? options.onError(result.error) : router.push("/404");
50
+ options?.onError ? options.onError(result.error) : defaultOnError(result.error, router);
46
51
  }
47
52
  else if (result.data) {
48
53
  options?.onSuccess?.(result.data);
@@ -0,0 +1,2 @@
1
+ export * from "./z-page/infer-params";
2
+ export * from "./z-page/resolve-params";
@@ -0,0 +1,2 @@
1
+ export * from "./z-page/infer-params";
2
+ export * from "./z-page/resolve-params";
@@ -0,0 +1,24 @@
1
+ import type { ZodObjectShape, InferZodObjectShapeOutput } from "../../utils/types";
2
+ /** Helper to infer a single param type */
3
+ type InferParam<T, K extends string> = K extends keyof T ? (T[K] extends ZodObjectShape ? InferZodObjectShapeOutput<T[K]> : never) : never;
4
+ /** Inferred params with Promise wrappers (for async page props) */
5
+ type InferZPageParamsPromises<T> = (T extends {
6
+ routeParams: ZodObjectShape;
7
+ } ? {
8
+ routeParams: Promise<InferParam<T, "routeParams">>;
9
+ } : {}) & (T extends {
10
+ searchParams: ZodObjectShape;
11
+ } ? {
12
+ searchParams: Promise<InferParam<T, "searchParams">>;
13
+ } : {});
14
+ /** Inferred params (unwrapped) */
15
+ type InferZPageParams<T> = (T extends {
16
+ routeParams: ZodObjectShape;
17
+ } ? {
18
+ routeParams: InferParam<T, "routeParams">;
19
+ } : {}) & (T extends {
20
+ searchParams: ZodObjectShape;
21
+ } ? {
22
+ searchParams: InferParam<T, "searchParams">;
23
+ } : {});
24
+ export type { InferZPageParamsPromises, InferZPageParams };
@@ -0,0 +1,14 @@
1
+ import type { OnZodError } from "../../server/z-page/utils/types";
2
+ type ResolveZPageParamsInput<RP, SP> = {
3
+ routeParams?: Promise<RP>;
4
+ searchParams?: Promise<SP>;
5
+ };
6
+ type ResolveZPageParamsResult<RP, SP> = {
7
+ routeParams: RP;
8
+ searchParams: SP;
9
+ };
10
+ type ResolveZPageParamsOptions = {
11
+ onError?: OnZodError;
12
+ };
13
+ export declare function resolveZPageParams<RP, SP>(paramsPromise: ResolveZPageParamsInput<RP, SP>, options?: ResolveZPageParamsOptions): Promise<ResolveZPageParamsResult<RP, SP>>;
14
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
- import { defaultOnError } from "../utils/helper";
3
- export async function resolveParams(paramsPromise, options = {}) {
2
+ import { defaultOnError } from "../../server/z-page/utils/setup";
3
+ export async function resolveZPageParams(paramsPromise, options = {}) {
4
4
  const result = {};
5
5
  const onError = options.onError ?? defaultOnError;
6
6
  if (paramsPromise.routeParams) {
@@ -1,47 +1,47 @@
1
1
  import React from "react";
2
- import { z } from "zod";
3
- import { type ZodObject, type OnError } from "../utils/helper";
4
- import type { NextPageProps } from "../types";
2
+ import type { NextPageProps, OnZodError } from "../utils/types";
3
+ import type { InferZodObjectShapeOutput, ZodObjectShape } from "../../../utils/types";
5
4
  /** Return type for zPage */
6
5
  type ZPageReturn = (props: NextPageProps) => React.ReactNode | Promise<React.ReactNode>;
7
- export declare function zPage<RP extends ZodObject, SP extends ZodObject>(cfg: {
6
+ type InferOutput<T extends ZodObjectShape> = InferZodObjectShapeOutput<T>;
7
+ export declare function zPage<RP extends ZodObjectShape, SP extends ZodObjectShape>(cfg: {
8
8
  params: {
9
9
  routeParams: RP;
10
10
  searchParams: SP;
11
11
  };
12
12
  resolve?: true;
13
- onError?: OnError;
13
+ onError?: OnZodError;
14
14
  loadingHandler?: React.ReactNode;
15
15
  handler: (input: {
16
- routeParams: z.output<RP>;
17
- searchParams: z.output<SP>;
16
+ routeParams: InferOutput<RP>;
17
+ searchParams: InferOutput<SP>;
18
18
  }) => React.ReactNode | Promise<React.ReactNode>;
19
19
  }): ZPageReturn;
20
- export declare function zPage<RP extends ZodObject>(cfg: {
20
+ export declare function zPage<RP extends ZodObjectShape>(cfg: {
21
21
  params: {
22
22
  routeParams: RP;
23
23
  searchParams?: undefined;
24
24
  };
25
25
  resolve?: true;
26
- onError?: OnError;
26
+ onError?: OnZodError;
27
27
  loadingHandler?: React.ReactNode;
28
28
  handler: (input: {
29
- routeParams: z.output<RP>;
29
+ routeParams: InferOutput<RP>;
30
30
  }) => React.ReactNode | Promise<React.ReactNode>;
31
31
  }): ZPageReturn;
32
- export declare function zPage<SP extends ZodObject>(cfg: {
32
+ export declare function zPage<SP extends ZodObjectShape>(cfg: {
33
33
  params: {
34
34
  routeParams?: undefined;
35
35
  searchParams: SP;
36
36
  };
37
37
  resolve?: true;
38
- onError?: OnError;
38
+ onError?: OnZodError;
39
39
  loadingHandler?: React.ReactNode;
40
40
  handler: (input: {
41
- searchParams: z.output<SP>;
41
+ searchParams: InferOutput<SP>;
42
42
  }) => React.ReactNode | Promise<React.ReactNode>;
43
43
  }): ZPageReturn;
44
- export declare function zPage<RP extends ZodObject, SP extends ZodObject>(cfg: {
44
+ export declare function zPage<RP extends ZodObjectShape, SP extends ZodObjectShape>(cfg: {
45
45
  params: {
46
46
  routeParams: RP;
47
47
  searchParams: SP;
@@ -50,11 +50,11 @@ export declare function zPage<RP extends ZodObject, SP extends ZodObject>(cfg: {
50
50
  onError?: never;
51
51
  loadingHandler?: never;
52
52
  handler: (input: {
53
- routeParams: Promise<z.output<RP>>;
54
- searchParams: Promise<z.output<SP>>;
53
+ routeParams: Promise<InferOutput<RP>>;
54
+ searchParams: Promise<InferOutput<SP>>;
55
55
  }) => React.ReactNode | Promise<React.ReactNode>;
56
56
  }): ZPageReturn;
57
- export declare function zPage<RP extends ZodObject>(cfg: {
57
+ export declare function zPage<RP extends ZodObjectShape>(cfg: {
58
58
  params: {
59
59
  routeParams: RP;
60
60
  searchParams?: undefined;
@@ -63,10 +63,10 @@ export declare function zPage<RP extends ZodObject>(cfg: {
63
63
  onError?: never;
64
64
  loadingHandler?: never;
65
65
  handler: (input: {
66
- routeParams: Promise<z.output<RP>>;
66
+ routeParams: Promise<InferOutput<RP>>;
67
67
  }) => React.ReactNode | Promise<React.ReactNode>;
68
68
  }): ZPageReturn;
69
- export declare function zPage<SP extends ZodObject>(cfg: {
69
+ export declare function zPage<SP extends ZodObjectShape>(cfg: {
70
70
  params: {
71
71
  routeParams?: undefined;
72
72
  searchParams: SP;
@@ -75,7 +75,7 @@ export declare function zPage<SP extends ZodObject>(cfg: {
75
75
  onError?: never;
76
76
  loadingHandler?: never;
77
77
  handler: (input: {
78
- searchParams: Promise<z.output<SP>>;
78
+ searchParams: Promise<InferOutput<SP>>;
79
79
  }) => React.ReactNode | Promise<React.ReactNode>;
80
80
  }): ZPageReturn;
81
81
  export {};
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Suspense } from "react";
3
- import { setup } from "../utils/helper";
3
+ import { setup } from "../utils/setup";
4
4
  // ------------- IMPLEMENTATION -------------
5
5
  export function zPage(cfg) {
6
6
  const shouldResolve = cfg.resolve !== false;
@@ -1,3 +1 @@
1
1
  export { zPage } from "./fns/z-page";
2
- export { resolveParams } from "./helpers/resolve-params";
3
- export type { InferParamsPromises, InferParams } from "./helpers/infer-props";
@@ -1,2 +1 @@
1
1
  export { zPage } from "./fns/z-page";
2
- export { resolveParams } from "./helpers/resolve-params";
@@ -0,0 +1,16 @@
1
+ import type { NextPageProps, OnZodError } from "./types";
2
+ import type { ZodObjectShape } from "../../../utils/types";
3
+ export declare const defaultOnError: OnZodError;
4
+ export declare function setup<RP extends ZodObjectShape, SP extends ZodObjectShape>(params: {
5
+ routeParams?: RP;
6
+ searchParams?: SP;
7
+ }, onError?: OnZodError): {
8
+ createValidatedPromises: (props: NextPageProps) => {
9
+ routeParams: Promise<Record<string, unknown>> | undefined;
10
+ searchParams: Promise<Record<string, unknown>> | undefined;
11
+ };
12
+ resolveParams: (promises: {
13
+ routeParams: Promise<Record<string, unknown>> | undefined;
14
+ searchParams: Promise<Record<string, unknown>> | undefined;
15
+ }) => Promise<Record<string, unknown>>;
16
+ };
@@ -1,12 +1,13 @@
1
1
  import { z } from "zod";
2
2
  import { redirect } from "next/navigation";
3
+ import { toZodObject } from "../../../utils/to-zod-object";
3
4
  export const defaultOnError = (e) => {
4
5
  console.log(e);
5
6
  redirect("/404");
6
7
  };
7
8
  export function setup(params, onError = defaultOnError) {
8
- const rpSchema = params.routeParams;
9
- const spSchema = params.searchParams;
9
+ const rpSchema = params.routeParams ? toZodObject(params.routeParams) : undefined;
10
+ const spSchema = params.searchParams ? toZodObject(params.searchParams) : undefined;
10
11
  /** Creates validated promises from Next.js page props */
11
12
  function createValidatedPromises(props) {
12
13
  return {
@@ -1,10 +1,8 @@
1
- import { z, type ZodRawShape } from "zod";
1
+ import { z } from "zod";
2
2
  /** Next.js page props type */
3
3
  export type NextPageProps = {
4
4
  params: Promise<Record<string, string | string[]>>;
5
5
  searchParams: Promise<Record<string, string | string[] | undefined>>;
6
6
  };
7
- /** Enforces that routeParams/searchParams must be z.object(...) */
8
- export type ZodObject = z.ZodObject<ZodRawShape>;
9
7
  /** Error handler type */
10
- export type OnError = (error: z.ZodError) => never | void;
8
+ export type OnZodError = (error: z.ZodError) => never | void;
@@ -0,0 +1,4 @@
1
+ import { z, type ZodRawShape } from "zod";
2
+ import type { ZodObjectShape } from "./types";
3
+ /** Wrap a raw shape in z.object() if it's not already a ZodObject */
4
+ export declare function toZodObject(schema: ZodObjectShape): z.ZodObject<ZodRawShape>;
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ /** Wrap a raw shape in z.object() if it's not already a ZodObject */
3
+ export function toZodObject(schema) {
4
+ if (schema instanceof z.ZodObject)
5
+ return schema;
6
+ return z.object(schema);
7
+ }
@@ -0,0 +1,7 @@
1
+ import { z, type ZodRawShape } from "zod";
2
+ /** A z.object(...) schema */
3
+ export type ZodObject<T extends ZodRawShape = ZodRawShape> = z.ZodObject<T>;
4
+ /** Plain object shape or z.object() - accepts either format */
5
+ export type ZodObjectShape = ZodRawShape | ZodObject;
6
+ /** Infer output type from either raw shape or ZodObject */
7
+ export type InferZodObjectShapeOutput<T extends ZodObjectShape> = T extends ZodObject<infer S> ? z.output<z.ZodObject<S>> : T extends ZodRawShape ? z.output<z.ZodObject<T>> : never;
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bb-labs/next-router",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "author": "Beepbop",
5
5
  "homepage": "https://github.com/beepbop-labs/next-router",
6
6
  "keywords": [
@@ -21,7 +21,8 @@
21
21
  ],
22
22
  "exports": {
23
23
  ".": "./dist/server/index.js",
24
- "./client": "./dist/client/index.js"
24
+ "./client": "./dist/client/index.js",
25
+ "./common": "./dist/common/index.js"
25
26
  },
26
27
  "scripts": {
27
28
  "clean": "rm -rf dist",
@@ -1,12 +0,0 @@
1
- import { z, type ZodObject, type ZodRawShape } from "zod";
2
- type InferParamsPromises<T> = ("routeParams" extends keyof T ? (T["routeParams"] extends ZodObject<ZodRawShape> ? {
3
- routeParams: Promise<z.output<T["routeParams"]>>;
4
- } : {}) : {}) & ("searchParams" extends keyof T ? (T["searchParams"] extends ZodObject<ZodRawShape> ? {
5
- searchParams: Promise<z.output<T["searchParams"]>>;
6
- } : {}) : {});
7
- type InferParams<T> = ("routeParams" extends keyof T ? (T["routeParams"] extends ZodObject<ZodRawShape> ? {
8
- routeParams: z.output<T["routeParams"]>;
9
- } : {}) : {}) & ("searchParams" extends keyof T ? (T["searchParams"] extends ZodObject<ZodRawShape> ? {
10
- searchParams: z.output<T["searchParams"]>;
11
- } : {}) : {});
12
- export type { InferParamsPromises, InferParams };
@@ -1,14 +0,0 @@
1
- import { type OnError } from "../utils/helper";
2
- type ResolveParamsInput<RP, SP> = {
3
- routeParams?: Promise<RP>;
4
- searchParams?: Promise<SP>;
5
- };
6
- type ResolveParamsResult<RP, SP> = {
7
- routeParams: RP;
8
- searchParams: SP;
9
- };
10
- type ResolveParamsOptions = {
11
- onError?: OnError;
12
- };
13
- export declare function resolveParams<RP, SP>(paramsPromise: ResolveParamsInput<RP, SP>, options?: ResolveParamsOptions): Promise<ResolveParamsResult<RP, SP>>;
14
- export {};
@@ -1,17 +0,0 @@
1
- import { z } from "zod";
2
- import type { NextPageProps, ZodObject, OnError } from "../types";
3
- export type { ZodObject, OnError };
4
- export declare const defaultOnError: OnError;
5
- export declare function setup<RP extends ZodObject, SP extends ZodObject>(params: {
6
- routeParams?: RP;
7
- searchParams?: SP;
8
- }, onError?: OnError): {
9
- createValidatedPromises: (props: NextPageProps) => {
10
- routeParams: Promise<z.core.output<RP>> | undefined;
11
- searchParams: Promise<z.core.output<SP>> | undefined;
12
- };
13
- resolveParams: (promises: {
14
- routeParams: Promise<z.core.output<RP>> | undefined;
15
- searchParams: Promise<z.core.output<SP>> | undefined;
16
- }) => Promise<Record<string, unknown>>;
17
- };
File without changes