rouzer 3.0.0 → 3.0.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/dist/client/index.d.ts +5 -2
- package/dist/client/index.js +3 -1
- package/dist/http.d.ts +5 -5
- package/dist/http.js +2 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +17 -0
- package/dist/internal.js +1 -0
- package/dist/server/router.d.ts +1 -1
- package/dist/type.d.ts +22 -0
- package/dist/type.js +21 -0
- package/dist/types/args.d.ts +51 -0
- package/dist/types/args.js +1 -0
- package/dist/types/handler.d.ts +31 -0
- package/dist/types/handler.js +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.js +1 -0
- package/dist/types/infer.d.ts +19 -0
- package/dist/types/infer.js +1 -0
- package/dist/types/path.d.ts +1 -0
- package/dist/types/path.js +1 -0
- package/dist/types/request.d.ts +35 -0
- package/dist/types/request.js +1 -0
- package/dist/types/response.d.ts +9 -0
- package/dist/types/response.js +1 -0
- package/dist/types/schema.d.ts +37 -0
- package/dist/types/schema.js +1 -0
- package/dist/types/server.d.ts +15 -0
- package/dist/types/server.js +1 -0
- package/dist/types.d.ts +12 -62
- package/docs/context.md +5 -15
- package/package.json +1 -1
- package/dist/route.d.ts +0 -56
- package/dist/route.js +0 -52
package/dist/client/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Promisable } from '../common.js';
|
|
2
2
|
import type { HttpAction, HttpResource, HttpRouteTree } from '../http.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { RouteArgs } from '../types/args.js';
|
|
4
|
+
import type { RouteRequest } from '../types/request.js';
|
|
5
|
+
import type { InferRouteResponse } from '../types/response.js';
|
|
6
|
+
import type { RouteSchema } from '../types/schema.js';
|
|
4
7
|
/** Client type inferred from an HTTP route tree passed to `createClient`. */
|
|
5
8
|
export type RouzerClient<TRoutes extends HttpRouteTree = Record<string, never>> = ReturnType<typeof createClient<TRoutes>>;
|
|
6
9
|
/**
|
|
@@ -80,7 +83,7 @@ export declare function createClient<TRoutes extends HttpRouteTree = Record<stri
|
|
|
80
83
|
/** Custom `fetch` implementation to use for requests. */
|
|
81
84
|
fetch?: typeof globalThis.fetch;
|
|
82
85
|
};
|
|
83
|
-
request: <T extends RouteRequest>({ path: pathBuilder, method, args
|
|
86
|
+
request: <T extends RouteRequest>({ path: pathBuilder, method, args, schema, }: T) => Promise<Response & {
|
|
84
87
|
json(): Promise<T['$result']>;
|
|
85
88
|
}>;
|
|
86
89
|
json: <T extends RouteRequest>(props: T) => Promise<T['$result']>;
|
package/dist/client/index.js
CHANGED
|
@@ -12,7 +12,8 @@ export function createClient(config) {
|
|
|
12
12
|
const baseURL = config.baseURL.replace(/\/?$/, '/');
|
|
13
13
|
const defaultHeaders = config.headers && shake(config.headers);
|
|
14
14
|
const fetch = config.fetch ?? globalThis.fetch;
|
|
15
|
-
async function request({ path: pathBuilder, method, args
|
|
15
|
+
async function request({ path: pathBuilder, method, args, schema, }) {
|
|
16
|
+
let { path, query, body, headers, ...init } = args;
|
|
16
17
|
if (schema.path) {
|
|
17
18
|
path = schema.path.parse(path);
|
|
18
19
|
}
|
|
@@ -48,6 +49,7 @@ export function createClient(config) {
|
|
|
48
49
|
headers = schema.headers.parse(headers);
|
|
49
50
|
}
|
|
50
51
|
return fetch(url, {
|
|
52
|
+
...init,
|
|
51
53
|
method,
|
|
52
54
|
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
53
55
|
headers: (headers ?? defaultHeaders),
|
package/dist/http.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RoutePattern } from '@remix-run/route-pattern';
|
|
2
|
-
import type { RouteRequestFactory
|
|
2
|
+
import type { RouteRequestFactory } from './types/request.js';
|
|
3
|
+
import type { RouteSchema } from './types/schema.js';
|
|
3
4
|
/** HTTP methods supported by Rouzer action declarations. */
|
|
4
5
|
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
5
6
|
/**
|
|
@@ -61,7 +62,6 @@ export declare function put<const T extends RouteSchema>(schema: T): HttpAction<
|
|
|
61
62
|
export declare function patch<const P extends string, const T extends RouteSchema>(path: P, schema: T): HttpAction<P, T, 'PATCH'>;
|
|
62
63
|
export declare function patch<const T extends RouteSchema>(schema: T): HttpAction<'', T, 'PATCH'>;
|
|
63
64
|
/** Declare a DELETE action, optionally with an action-local path segment. */
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
export { del as delete };
|
|
65
|
+
declare function deleteAction<const P extends string, const T extends RouteSchema>(path: P, schema: T): HttpAction<P, T, 'DELETE'>;
|
|
66
|
+
declare function deleteAction<const T extends RouteSchema>(schema: T): HttpAction<'', T, 'DELETE'>;
|
|
67
|
+
export { deleteAction as delete };
|
package/dist/http.js
CHANGED
|
@@ -25,11 +25,10 @@ export function put(pathOrSchema, schema) {
|
|
|
25
25
|
export function patch(pathOrSchema, schema) {
|
|
26
26
|
return action('PATCH', pathOrSchema, schema);
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
function deleteAction(pathOrSchema, schema) {
|
|
29
29
|
return action('DELETE', pathOrSchema, schema);
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
export { del as delete };
|
|
31
|
+
export { deleteAction as delete };
|
|
33
32
|
function action(method, pathOrSchema, schema) {
|
|
34
33
|
const path = typeof pathOrSchema === 'string' ? RoutePattern.parse(pathOrSchema) : undefined;
|
|
35
34
|
schema ??= typeof pathOrSchema === 'string' ? {} : pathOrSchema;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RoutePattern } from '@remix-run/route-pattern';
|
|
2
|
+
import type { RouteRequestFactory, RouteSchema } from './types.js';
|
|
3
|
+
/** @internal */
|
|
4
|
+
export type RouteSchemaMap = {
|
|
5
|
+
GET?: RouteSchema;
|
|
6
|
+
POST?: RouteSchema;
|
|
7
|
+
PUT?: RouteSchema;
|
|
8
|
+
PATCH?: RouteSchema;
|
|
9
|
+
DELETE?: RouteSchema;
|
|
10
|
+
};
|
|
11
|
+
/** @internal */
|
|
12
|
+
export type Route<P extends string = string, T extends RouteSchemaMap = RouteSchemaMap> = {
|
|
13
|
+
path: RoutePattern<P>;
|
|
14
|
+
methods: T;
|
|
15
|
+
} & {
|
|
16
|
+
[K in keyof T]: RouteRequestFactory<Extract<T[K], RouteSchema>, P>;
|
|
17
|
+
};
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/server/router.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { HattipHandler } from '@hattip/core';
|
|
2
2
|
import { ApplyMiddleware, chain, ExtractMiddleware, MiddlewareChain, MiddlewareTypes } from 'alien-middleware';
|
|
3
3
|
import type { HttpRouteTree } from '../http.js';
|
|
4
|
-
import type { RouteRequestHandlerMap } from '
|
|
4
|
+
import type { RouteRequestHandlerMap } from '../types/server.js';
|
|
5
5
|
export { chain };
|
|
6
6
|
/** Configuration for `createRouter`. */
|
|
7
7
|
export type RouterConfig = {
|
package/dist/type.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Unchecked } from './common.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create a compile-time-only marker for an action's JSON response payload type.
|
|
4
|
+
*
|
|
5
|
+
* @remarks `$type<T>()` does not perform runtime validation. It lets Rouzer type
|
|
6
|
+
* server handler return values and client action functions for HTTP actions
|
|
7
|
+
* whose responses are expected to be JSON.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { $type } from 'rouzer'
|
|
12
|
+
* import * as http from 'rouzer/http'
|
|
13
|
+
*
|
|
14
|
+
* const hello = http.get('hello/:name', {
|
|
15
|
+
* response: $type<{ message: string }>(),
|
|
16
|
+
* })
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function $type<T>(): Unchecked<T>;
|
|
20
|
+
export declare namespace $type {
|
|
21
|
+
var symbol: symbol;
|
|
22
|
+
}
|
package/dist/type.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a compile-time-only marker for an action's JSON response payload type.
|
|
3
|
+
*
|
|
4
|
+
* @remarks `$type<T>()` does not perform runtime validation. It lets Rouzer type
|
|
5
|
+
* server handler return values and client action functions for HTTP actions
|
|
6
|
+
* whose responses are expected to be JSON.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { $type } from 'rouzer'
|
|
11
|
+
* import * as http from 'rouzer/http'
|
|
12
|
+
*
|
|
13
|
+
* const hello = http.get('hello/:name', {
|
|
14
|
+
* response: $type<{ message: string }>(),
|
|
15
|
+
* })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function $type() {
|
|
19
|
+
return $type.symbol;
|
|
20
|
+
}
|
|
21
|
+
$type.symbol = Symbol();
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { MatchParams } from '@remix-run/route-pattern/match';
|
|
2
|
+
import type * as z from 'zod';
|
|
3
|
+
import type { MutationRouteSchema, QueryRouteSchema, RouteSchema } from './schema.js';
|
|
4
|
+
declare class Any {
|
|
5
|
+
private isAny;
|
|
6
|
+
}
|
|
7
|
+
type PathArgs<T, P extends string> = T extends {
|
|
8
|
+
path: infer TPath;
|
|
9
|
+
} ? {} extends z.infer<TPath> ? {
|
|
10
|
+
[K in keyof T as 'path']?: z.infer<TPath>;
|
|
11
|
+
} : {
|
|
12
|
+
[K in keyof T as 'path']: z.infer<TPath>;
|
|
13
|
+
} : MatchParams<P> extends infer TParams ? {} extends TParams ? {
|
|
14
|
+
[K in keyof T as 'path']?: TParams;
|
|
15
|
+
} : {
|
|
16
|
+
[K in keyof T as 'path']: TParams;
|
|
17
|
+
} : unknown;
|
|
18
|
+
type QueryArgs<T> = T extends QueryRouteSchema & {
|
|
19
|
+
query: infer TQuery;
|
|
20
|
+
} ? {} extends z.infer<TQuery> ? {
|
|
21
|
+
[K in keyof T as 'query']?: z.infer<TQuery>;
|
|
22
|
+
} : {
|
|
23
|
+
[K in keyof T as 'query']: z.infer<TQuery>;
|
|
24
|
+
} : unknown;
|
|
25
|
+
type MutationArgs<T> = T extends MutationRouteSchema ? T extends {
|
|
26
|
+
body: infer TBody;
|
|
27
|
+
} ? {} extends z.infer<TBody> ? {
|
|
28
|
+
[K in keyof T as 'body']?: z.infer<TBody>;
|
|
29
|
+
} : {
|
|
30
|
+
[K in keyof T as 'body']: z.infer<TBody>;
|
|
31
|
+
} : {
|
|
32
|
+
body?: unknown;
|
|
33
|
+
} : unknown;
|
|
34
|
+
/**
|
|
35
|
+
* Arguments accepted by a client action function or low-level request factory.
|
|
36
|
+
*
|
|
37
|
+
* @remarks The type is derived from an action schema and route pattern. `path`,
|
|
38
|
+
* `query`, `body`, and `headers` are validated by the client before `fetch` when
|
|
39
|
+
* a matching schema exists. Other `RequestInit` fields are forwarded to `fetch`,
|
|
40
|
+
* except `method`, `body`, and `headers`, which Rouzer derives from the action
|
|
41
|
+
* schema and call arguments.
|
|
42
|
+
*/
|
|
43
|
+
export type RouteArgs<T extends RouteSchema = any, P extends string = string> = ([T] extends [Any] ? {
|
|
44
|
+
query?: any;
|
|
45
|
+
body?: any;
|
|
46
|
+
path?: any;
|
|
47
|
+
} : QueryArgs<T> & MutationArgs<T> & PathArgs<T, P>) & Omit<RequestInit, 'method' | 'body' | 'headers'> & {
|
|
48
|
+
/** Headers for this request. Undefined values are removed before `fetch`. */
|
|
49
|
+
headers?: Record<string, string | undefined>;
|
|
50
|
+
};
|
|
51
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { MatchParams } from '@remix-run/route-pattern/match';
|
|
2
|
+
import type { AnyMiddlewareChain, MiddlewareContext } from 'alien-middleware';
|
|
3
|
+
import type * as z from 'zod';
|
|
4
|
+
import { Promisable } from '../common.js';
|
|
5
|
+
import type { HttpAction } from '../http.js';
|
|
6
|
+
import type { InferRouteResponse } from './response.js';
|
|
7
|
+
import type { RouteSchema } from './schema.js';
|
|
8
|
+
type RequestContext<TMiddleware extends AnyMiddlewareChain> = MiddlewareContext<TMiddleware>;
|
|
9
|
+
export type RouteRequestHandler<TMiddleware extends AnyMiddlewareChain, TArgs extends object, TResult> = (context: RequestContext<TMiddleware> & TArgs) => Promisable<TResult | Response>;
|
|
10
|
+
export type InferActionHandler<TMiddleware extends AnyMiddlewareChain, TAction extends HttpAction, TPath extends string> = TAction['method'] extends 'GET' ? RouteRequestHandler<TMiddleware, {
|
|
11
|
+
path: TAction['schema'] extends {
|
|
12
|
+
path: any;
|
|
13
|
+
} ? z.infer<TAction['schema']['path']> : MatchParams<TPath>;
|
|
14
|
+
query: TAction['schema'] extends {
|
|
15
|
+
query: any;
|
|
16
|
+
} ? z.infer<TAction['schema']['query']> : undefined;
|
|
17
|
+
headers: TAction['schema'] extends {
|
|
18
|
+
headers: any;
|
|
19
|
+
} ? z.infer<TAction['schema']['headers']> : undefined;
|
|
20
|
+
}, InferRouteResponse<Extract<TAction['schema'], RouteSchema>>> : RouteRequestHandler<TMiddleware, {
|
|
21
|
+
path: TAction['schema'] extends {
|
|
22
|
+
path: any;
|
|
23
|
+
} ? z.infer<TAction['schema']['path']> : MatchParams<TPath>;
|
|
24
|
+
body: TAction['schema'] extends {
|
|
25
|
+
body: any;
|
|
26
|
+
} ? z.infer<TAction['schema']['body']> : undefined;
|
|
27
|
+
headers: TAction['schema'] extends {
|
|
28
|
+
headers: any;
|
|
29
|
+
} ? z.infer<TAction['schema']['headers']> : undefined;
|
|
30
|
+
}, InferRouteResponse<Extract<TAction['schema'], RouteSchema>>>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as z from 'zod';
|
|
2
|
+
import type { MutationRouteSchema, RouteSchema } from './schema.js';
|
|
3
|
+
import type { RouteRequestFactory } from './request.js';
|
|
4
|
+
type InferRouteSchemaBody<TSchema> = TSchema extends MutationRouteSchema ? TSchema extends {
|
|
5
|
+
body: infer TBody;
|
|
6
|
+
} ? z.infer<TBody> : unknown : never;
|
|
7
|
+
type InferRouteArgsBody<TArgs> = TArgs extends {
|
|
8
|
+
body?: infer TBody;
|
|
9
|
+
} ? TBody : never;
|
|
10
|
+
/**
|
|
11
|
+
* Infer the request body type from an action schema or request factory.
|
|
12
|
+
*
|
|
13
|
+
* @remarks HTTP action schemas can be inspected with
|
|
14
|
+
* `InferRouteBody<typeof action.schema>`. Request factories for mutation actions
|
|
15
|
+
* infer their `body` argument type. Schemas without a body schema infer
|
|
16
|
+
* `unknown`.
|
|
17
|
+
*/
|
|
18
|
+
export type InferRouteBody<T> = T extends RouteRequestFactory<any, any> ? InferRouteArgsBody<T['$args']> : T extends RouteSchema ? InferRouteSchemaBody<T> : never;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Join<A extends string, B extends string> = A extends '' ? B : B extends '' ? A : `${A}/${B}`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { RoutePattern } from '@remix-run/route-pattern';
|
|
2
|
+
import type { RouteArgs } from './args.js';
|
|
3
|
+
import type { InferRouteResponse } from './response.js';
|
|
4
|
+
import type { RouteSchema } from './schema.js';
|
|
5
|
+
/**
|
|
6
|
+
* Request descriptor produced by an HTTP action request factory.
|
|
7
|
+
*
|
|
8
|
+
* @remarks Pass this object to `client.request(...)` for a raw `Response` or
|
|
9
|
+
* `client.json(...)` for parsed JSON handling.
|
|
10
|
+
*/
|
|
11
|
+
export type RouteRequest<TResult = any> = {
|
|
12
|
+
/** Method schema used for client-side validation. */
|
|
13
|
+
schema: RouteSchema;
|
|
14
|
+
/** Parsed route pattern used to generate the request URL. */
|
|
15
|
+
path: RoutePattern;
|
|
16
|
+
/** HTTP method to send. */
|
|
17
|
+
method: string;
|
|
18
|
+
/** Validated route arguments and request options. */
|
|
19
|
+
args: RouteArgs;
|
|
20
|
+
/** Phantom result type consumed by `client.json(...)`. */
|
|
21
|
+
$result: TResult;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Callable factory attached to an HTTP action.
|
|
25
|
+
*
|
|
26
|
+
* @remarks Calling a factory validates no data by itself; it creates a typed
|
|
27
|
+
* `RouteRequest` descriptor for `createClient` to validate and send.
|
|
28
|
+
*/
|
|
29
|
+
export type RouteRequestFactory<T extends RouteSchema, P extends string> = {
|
|
30
|
+
(...p: RouteArgs<T, P> extends infer TArgs ? {} extends TArgs ? [args?: TArgs] : [args: TArgs] : never): RouteRequest<InferRouteResponse<T>>;
|
|
31
|
+
/** Inferred argument type for this request factory. */
|
|
32
|
+
$args: RouteArgs<T, P>;
|
|
33
|
+
/** Inferred JSON response type for this request factory. */
|
|
34
|
+
$response: InferRouteResponse<T>;
|
|
35
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Unchecked, RouteSchema } from './schema.js';
|
|
2
|
+
/** `Response` whose `.json()` method resolves to a known payload type. */
|
|
3
|
+
export type RouteResponse<TResult = any> = Response & {
|
|
4
|
+
json(): Promise<TResult>;
|
|
5
|
+
};
|
|
6
|
+
/** Infer the JSON response payload type from an action schema. */
|
|
7
|
+
export type InferRouteResponse<T extends RouteSchema> = T extends {
|
|
8
|
+
response: Unchecked<infer TResponse>;
|
|
9
|
+
} ? TResponse : void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
import { Unchecked } from '../common.js';
|
|
3
|
+
/**
|
|
4
|
+
* Compile-time-only marker used by `$type<T>()` for unchecked response types.
|
|
5
|
+
*
|
|
6
|
+
* @remarks Application code should usually call `$type<T>()` instead of naming
|
|
7
|
+
* this marker directly.
|
|
8
|
+
*/
|
|
9
|
+
export type { Unchecked };
|
|
10
|
+
/** Schema shape for `GET` route methods. */
|
|
11
|
+
export type QueryRouteSchema = {
|
|
12
|
+
/** Optional Zod object used to validate path params. */
|
|
13
|
+
path?: z.ZodObject<any>;
|
|
14
|
+
/** Optional Zod object used to validate URL query params. */
|
|
15
|
+
query?: z.ZodObject<any>;
|
|
16
|
+
/** `GET` routes do not accept request bodies. */
|
|
17
|
+
body?: never;
|
|
18
|
+
/** Optional Zod object used to validate request headers. */
|
|
19
|
+
headers?: z.ZodObject<any>;
|
|
20
|
+
/** Optional compile-time-only JSON response type marker. */
|
|
21
|
+
response?: Unchecked<any>;
|
|
22
|
+
};
|
|
23
|
+
/** Schema shape for mutation route methods. */
|
|
24
|
+
export type MutationRouteSchema = {
|
|
25
|
+
/** Optional Zod object used to validate path params. */
|
|
26
|
+
path?: z.ZodObject<any>;
|
|
27
|
+
/** Mutation routes do not accept query schemas. */
|
|
28
|
+
query?: never;
|
|
29
|
+
/** Optional Zod schema used to validate the JSON request body. */
|
|
30
|
+
body?: z.ZodType<any, any>;
|
|
31
|
+
/** Optional Zod object used to validate request headers. */
|
|
32
|
+
headers?: z.ZodObject<any>;
|
|
33
|
+
/** Optional compile-time-only JSON response type marker. */
|
|
34
|
+
response?: Unchecked<any>;
|
|
35
|
+
};
|
|
36
|
+
/** Any HTTP action schema Rouzer can execute. */
|
|
37
|
+
export type RouteSchema = QueryRouteSchema | MutationRouteSchema;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AnyMiddlewareChain, MiddlewareChain } from 'alien-middleware';
|
|
2
|
+
import type { HttpAction, HttpResource, HttpRouteTree } from '../http.js';
|
|
3
|
+
import type { InferActionHandler } from './handler.js';
|
|
4
|
+
import type { Join } from './path.js';
|
|
5
|
+
/**
|
|
6
|
+
* Handler map shape required by `createRouter().use(routes, handlers)`.
|
|
7
|
+
*
|
|
8
|
+
* @remarks The handler object mirrors the HTTP route tree. Resource nodes become
|
|
9
|
+
* nested handler objects, while action nodes become direct handler functions.
|
|
10
|
+
* Handler context is inferred from middleware plus accumulated path params,
|
|
11
|
+
* query/body schemas, and header schemas.
|
|
12
|
+
*/
|
|
13
|
+
export type RouteRequestHandlerMap<TRoutes extends HttpRouteTree = HttpRouteTree, TMiddleware extends AnyMiddlewareChain = MiddlewareChain, TPrefix extends string = ''> = {
|
|
14
|
+
[K in keyof TRoutes]: TRoutes[K] extends HttpResource<infer P, infer C> ? RouteRequestHandlerMap<C, TMiddleware, Join<TPrefix, P>> : TRoutes[K] extends HttpAction<infer P, any, any> ? InferActionHandler<TMiddleware, TRoutes[K], Join<TPrefix, P>> : never;
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RoutePattern } from '@remix-run/route-pattern';
|
|
2
1
|
import type { MatchParams } from '@remix-run/route-pattern/match';
|
|
2
|
+
import { RoutePattern } from '@remix-run/route-pattern';
|
|
3
3
|
import * as z from 'zod';
|
|
4
4
|
import { Unchecked } from './common.js';
|
|
5
5
|
/**
|
|
@@ -35,47 +35,8 @@ export type MutationRouteSchema = {
|
|
|
35
35
|
/** Optional compile-time-only JSON response type marker. */
|
|
36
36
|
response?: Unchecked<any>;
|
|
37
37
|
};
|
|
38
|
-
/**
|
|
39
|
-
* Method schema map accepted by the low-level `route(...)` helper.
|
|
40
|
-
*
|
|
41
|
-
* @remarks `GET` validates query input and mutation methods validate JSON body
|
|
42
|
-
* input. Prefer `rouzer/http` actions for route trees registered with
|
|
43
|
-
* `createRouter().use(...)` or `createClient({ routes })`.
|
|
44
|
-
*/
|
|
45
|
-
export type RouteSchemaMap = {
|
|
46
|
-
GET?: QueryRouteSchema;
|
|
47
|
-
POST?: MutationRouteSchema;
|
|
48
|
-
PUT?: MutationRouteSchema;
|
|
49
|
-
PATCH?: MutationRouteSchema;
|
|
50
|
-
DELETE?: MutationRouteSchema;
|
|
51
|
-
ALL?: {
|
|
52
|
-
/** Optional Zod object used to validate path params. */
|
|
53
|
-
path?: z.ZodObject<any>;
|
|
54
|
-
/** Optional Zod object used to validate URL query params. */
|
|
55
|
-
query?: z.ZodObject<any>;
|
|
56
|
-
/** `ALL` fallback routes do not accept request bodies. */
|
|
57
|
-
body?: never;
|
|
58
|
-
/** Optional Zod object used to validate request headers. */
|
|
59
|
-
headers?: z.ZodObject<any>;
|
|
60
|
-
/** `ALL` fallback routes do not define typed JSON responses. */
|
|
61
|
-
response?: never;
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
/** Any route method schema Rouzer can execute. */
|
|
38
|
+
/** Any HTTP action schema Rouzer can execute. */
|
|
65
39
|
export type RouteSchema = QueryRouteSchema | MutationRouteSchema;
|
|
66
|
-
/**
|
|
67
|
-
* Low-level route map shape produced from `route(...)` declarations.
|
|
68
|
-
*
|
|
69
|
-
* @remarks The router and client shorthand registration APIs now expect
|
|
70
|
-
* `HttpRouteTree` values from the `rouzer/http` subpath. Use this type only for
|
|
71
|
-
* code that still works directly with low-level `route(...)` descriptors.
|
|
72
|
-
*/
|
|
73
|
-
export type Routes = {
|
|
74
|
-
[key: string]: {
|
|
75
|
-
path: RoutePattern;
|
|
76
|
-
methods: RouteSchemaMap;
|
|
77
|
-
};
|
|
78
|
-
};
|
|
79
40
|
declare class Any {
|
|
80
41
|
private isAny;
|
|
81
42
|
}
|
|
@@ -107,14 +68,13 @@ type MutationArgs<T> = T extends MutationRouteSchema ? T extends {
|
|
|
107
68
|
body?: unknown;
|
|
108
69
|
} : unknown;
|
|
109
70
|
/**
|
|
110
|
-
* Arguments accepted by a
|
|
111
|
-
* or a low-level `route.GET(...)` factory.
|
|
71
|
+
* Arguments accepted by a client action function or low-level request factory.
|
|
112
72
|
*
|
|
113
|
-
* @remarks The type is derived from
|
|
73
|
+
* @remarks The type is derived from an action schema and route pattern. `path`,
|
|
114
74
|
* `query`, `body`, and `headers` are validated by the client before `fetch` when
|
|
115
|
-
* a matching schema exists.
|
|
116
|
-
*
|
|
117
|
-
*
|
|
75
|
+
* a matching schema exists. Other `RequestInit` fields are forwarded to `fetch`,
|
|
76
|
+
* except `method`, `body`, and `headers`, which Rouzer derives from the action
|
|
77
|
+
* schema and call arguments.
|
|
118
78
|
*/
|
|
119
79
|
export type RouteArgs<T extends RouteSchema = any, P extends string = string> = ([T] extends [Any] ? {
|
|
120
80
|
query?: any;
|
|
@@ -125,7 +85,7 @@ export type RouteArgs<T extends RouteSchema = any, P extends string = string> =
|
|
|
125
85
|
headers?: Record<string, string | undefined>;
|
|
126
86
|
};
|
|
127
87
|
/**
|
|
128
|
-
* Request descriptor produced by an HTTP action
|
|
88
|
+
* Request descriptor produced by an HTTP action request factory.
|
|
129
89
|
*
|
|
130
90
|
* @remarks Pass this object to `client.request(...)` for a raw `Response` or
|
|
131
91
|
* `client.json(...)` for parsed JSON handling.
|
|
@@ -146,7 +106,7 @@ export type RouteRequest<TResult = any> = {
|
|
|
146
106
|
export type RouteResponse<TResult = any> = Response & {
|
|
147
107
|
json(): Promise<TResult>;
|
|
148
108
|
};
|
|
149
|
-
/** Infer the JSON response payload type from
|
|
109
|
+
/** Infer the JSON response payload type from an action schema. */
|
|
150
110
|
export type InferRouteResponse<T extends RouteSchema> = T extends {
|
|
151
111
|
response: Unchecked<infer TResponse>;
|
|
152
112
|
} ? TResponse : void;
|
|
@@ -157,26 +117,16 @@ type InferRouteArgsBody<TArgs> = TArgs extends {
|
|
|
157
117
|
body?: infer TBody;
|
|
158
118
|
} ? TBody : never;
|
|
159
119
|
/**
|
|
160
|
-
* Infer the request body type from
|
|
120
|
+
* Infer the request body type from an action schema or request factory.
|
|
161
121
|
*
|
|
162
122
|
* @remarks HTTP action schemas can be inspected with
|
|
163
|
-
* `InferRouteBody<typeof action.schema>`. Request factories for mutation
|
|
123
|
+
* `InferRouteBody<typeof action.schema>`. Request factories for mutation actions
|
|
164
124
|
* infer their `body` argument type. Schemas without a body schema infer
|
|
165
125
|
* `unknown`.
|
|
166
126
|
*/
|
|
167
127
|
export type InferRouteBody<T> = T extends RouteRequestFactory<any, any> ? InferRouteArgsBody<T['$args']> : T extends RouteSchema ? InferRouteSchemaBody<T> : never;
|
|
168
128
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* @remarks `GET` and `ALL` infer `never` because they do not accept request
|
|
172
|
-
* bodies. For `rouzer/http` actions, prefer
|
|
173
|
-
* `InferRouteBody<typeof action.schema>`.
|
|
174
|
-
*/
|
|
175
|
-
export type InferRouteMethodBody<TRoute extends {
|
|
176
|
-
methods: RouteSchemaMap;
|
|
177
|
-
}, TMethod extends keyof TRoute['methods']> = TMethod extends 'GET' | 'ALL' ? never : TMethod extends keyof TRoute ? InferRouteBody<TRoute[TMethod]> : InferRouteBody<Extract<TRoute['methods'][TMethod], RouteSchema>>;
|
|
178
|
-
/**
|
|
179
|
-
* Callable factory attached to an HTTP action or low-level `Route` method.
|
|
129
|
+
* Callable factory attached to an HTTP action.
|
|
180
130
|
*
|
|
181
131
|
* @remarks Calling a factory validates no data by itself; it creates a typed
|
|
182
132
|
* `RouteRequest` descriptor for `createClient` to validate and send.
|
package/docs/context.md
CHANGED
|
@@ -39,9 +39,8 @@ export const routes = { getProfile }
|
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
An action is a callable endpoint leaf. Use `http.get`, `http.post`, `http.put`,
|
|
42
|
-
`http.patch`, or `http.
|
|
43
|
-
|
|
44
|
-
URL pattern.
|
|
42
|
+
`http.patch`, or `http.delete` to declare one HTTP operation. The key you put the
|
|
43
|
+
action under is the client and handler name; the action path is the URL pattern.
|
|
45
44
|
|
|
46
45
|
Use `http.resource(path, children)` when several actions share a path prefix or
|
|
47
46
|
when you want nested client/handler namespaces:
|
|
@@ -83,7 +82,7 @@ Method schemas describe the request pieces Rouzer should validate:
|
|
|
83
82
|
| Action helper | Request schemas | Notes |
|
|
84
83
|
| ------------------------------------- | -------------------------------------- | ---------------- |
|
|
85
84
|
| `http.get(...)` | `path`, `query`, `headers`, `response` | No request body. |
|
|
86
|
-
| `http.post/put/patch/delete
|
|
85
|
+
| `http.post/put/patch/delete(...)` | `path`, `body`, `headers`, `response` | No query schema. |
|
|
87
86
|
|
|
88
87
|
If you omit a `path` schema, TypeScript infers path params from the pattern and
|
|
89
88
|
server handlers receive them as strings. Add a Zod `path` schema when you need
|
|
@@ -165,16 +164,6 @@ Default headers can be supplied with `headers`, per-request headers are merged o
|
|
|
165
164
|
top, and a custom `fetch` implementation can be supplied for tests or non-browser
|
|
166
165
|
runtimes.
|
|
167
166
|
|
|
168
|
-
### Low-level `route(...)` descriptors
|
|
169
|
-
|
|
170
|
-
The root package still exports `route(pattern, methods)`. It creates method-keyed
|
|
171
|
-
request descriptor factories such as `legacyRoute.GET(args)` for explicit
|
|
172
|
-
`client.request(...)` or `client.json(...)` calls.
|
|
173
|
-
|
|
174
|
-
Prefer `rouzer/http` route trees for shared server/client routing. The router and
|
|
175
|
-
client shorthand registration APIs expect `HttpAction`/`HttpResource` trees, not
|
|
176
|
-
the older method-map objects produced by `route(...)`.
|
|
177
|
-
|
|
178
167
|
## Lifecycle
|
|
179
168
|
|
|
180
169
|
1. Define shared HTTP actions/resources with `rouzer/http` and Zod schemas.
|
|
@@ -332,7 +321,8 @@ await client.profiles.update({
|
|
|
332
321
|
- Nested action `.request(...)` factories do not include parent resource paths;
|
|
333
322
|
prefer client action functions for nested resources.
|
|
334
323
|
- Extra `RequestInit` fields in route args, such as `signal` or `credentials`,
|
|
335
|
-
are
|
|
324
|
+
are forwarded by `createClient`; `method`, `body`, and `headers` are reserved
|
|
325
|
+
for Rouzer's action metadata and validated call arguments.
|
|
336
326
|
- The HTTP action API has no `ALL` fallback route. Declare explicit actions for
|
|
337
327
|
supported methods.
|
|
338
328
|
- Rouzer does not automatically set `Access-Control-Allow-Credentials`; set it in
|
package/package.json
CHANGED
package/dist/route.d.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { RoutePattern } from '@remix-run/route-pattern';
|
|
2
|
-
import { Unchecked } from './common.js';
|
|
3
|
-
import type { RouteRequestFactory, RouteSchema, RouteSchemaMap } from './types.js';
|
|
4
|
-
/**
|
|
5
|
-
* Create a compile-time-only marker for a route's JSON response payload type.
|
|
6
|
-
*
|
|
7
|
-
* @remarks `$type<T>()` does not perform runtime validation. It lets Rouzer type
|
|
8
|
-
* server handler return values and client action functions for routes whose
|
|
9
|
-
* responses are expected to be JSON.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```ts
|
|
13
|
-
* import { $type } from 'rouzer'
|
|
14
|
-
* import * as http from 'rouzer/http'
|
|
15
|
-
*
|
|
16
|
-
* const hello = http.get('hello/:name', {
|
|
17
|
-
* response: $type<{ message: string }>(),
|
|
18
|
-
* })
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export declare function $type<T>(): Unchecked<T>;
|
|
22
|
-
export declare namespace $type {
|
|
23
|
-
var symbol: symbol;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Low-level route declaration produced by `route(...)`.
|
|
27
|
-
*
|
|
28
|
-
* @remarks A `Route` stores the parsed URL pattern, the method schema map, and a
|
|
29
|
-
* request factory for each declared method. Use those factories with
|
|
30
|
-
* `client.request(...)` or `client.json(...)` when you need explicit response
|
|
31
|
-
* handling. For shared server/client route trees, prefer `rouzer/http` actions
|
|
32
|
-
* and resources; `createRouter().use(...)` and `createClient({ routes })` expect
|
|
33
|
-
* that HTTP route tree shape.
|
|
34
|
-
*/
|
|
35
|
-
export type Route<P extends string = string, T extends RouteSchemaMap = RouteSchemaMap> = {
|
|
36
|
-
/** Parsed route pattern used for request URL generation. */
|
|
37
|
-
path: RoutePattern<P>;
|
|
38
|
-
/** Method schemas declared for this route. */
|
|
39
|
-
methods: T;
|
|
40
|
-
} & {
|
|
41
|
-
[K in keyof T]: RouteRequestFactory<Extract<T[K], RouteSchema>, P>;
|
|
42
|
-
};
|
|
43
|
-
/**
|
|
44
|
-
* Declare one URL pattern and its supported HTTP method schemas.
|
|
45
|
-
*
|
|
46
|
-
* @remarks This helper creates low-level request descriptor factories. Prefer
|
|
47
|
-
* `rouzer/http` action helpers for routes that will be registered with
|
|
48
|
-
* `createRouter().use(...)` or mirrored by `createClient({ routes })`.
|
|
49
|
-
*
|
|
50
|
-
* @param pattern Route pattern parsed by `@remix-run/route-pattern`.
|
|
51
|
-
* @param methods Method schemas that describe request validation and optional
|
|
52
|
-
* response typing.
|
|
53
|
-
* @returns A route declaration with request factories such as `.GET(...)` and
|
|
54
|
-
* `.POST(...)` for the declared methods.
|
|
55
|
-
*/
|
|
56
|
-
export declare function route<P extends string, T extends RouteSchemaMap>(pattern: P, methods: T): Route<P, T>;
|
package/dist/route.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { RoutePattern } from '@remix-run/route-pattern';
|
|
2
|
-
import { mapEntries } from './common.js';
|
|
3
|
-
/**
|
|
4
|
-
* Create a compile-time-only marker for a route's JSON response payload type.
|
|
5
|
-
*
|
|
6
|
-
* @remarks `$type<T>()` does not perform runtime validation. It lets Rouzer type
|
|
7
|
-
* server handler return values and client action functions for routes whose
|
|
8
|
-
* responses are expected to be JSON.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* import { $type } from 'rouzer'
|
|
13
|
-
* import * as http from 'rouzer/http'
|
|
14
|
-
*
|
|
15
|
-
* const hello = http.get('hello/:name', {
|
|
16
|
-
* response: $type<{ message: string }>(),
|
|
17
|
-
* })
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export function $type() {
|
|
21
|
-
return $type.symbol;
|
|
22
|
-
}
|
|
23
|
-
$type.symbol = Symbol();
|
|
24
|
-
/**
|
|
25
|
-
* Declare one URL pattern and its supported HTTP method schemas.
|
|
26
|
-
*
|
|
27
|
-
* @remarks This helper creates low-level request descriptor factories. Prefer
|
|
28
|
-
* `rouzer/http` action helpers for routes that will be registered with
|
|
29
|
-
* `createRouter().use(...)` or mirrored by `createClient({ routes })`.
|
|
30
|
-
*
|
|
31
|
-
* @param pattern Route pattern parsed by `@remix-run/route-pattern`.
|
|
32
|
-
* @param methods Method schemas that describe request validation and optional
|
|
33
|
-
* response typing.
|
|
34
|
-
* @returns A route declaration with request factories such as `.GET(...)` and
|
|
35
|
-
* `.POST(...)` for the declared methods.
|
|
36
|
-
*/
|
|
37
|
-
export function route(pattern, methods) {
|
|
38
|
-
const path = RoutePattern.parse(pattern);
|
|
39
|
-
const createFetch = (method, schema) => (args = {}) => {
|
|
40
|
-
return {
|
|
41
|
-
schema,
|
|
42
|
-
path,
|
|
43
|
-
method,
|
|
44
|
-
args,
|
|
45
|
-
$result: undefined,
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
|
-
return Object.assign({ path, methods }, mapEntries(methods, (method, schema) => [
|
|
49
|
-
method,
|
|
50
|
-
createFetch(method, schema),
|
|
51
|
-
]));
|
|
52
|
-
}
|