@taserjs/router 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +24 -0
- package/dist/cjs/constants.cjs +17 -0
- package/dist/cjs/constants.cjs.map +1 -0
- package/dist/cjs/constants.d.cts +8 -0
- package/dist/cjs/create-context.cjs +8 -0
- package/dist/cjs/create-context.cjs.map +1 -0
- package/dist/cjs/create-context.d.cts +5 -0
- package/dist/cjs/define/handler.cjs +38 -0
- package/dist/cjs/define/handler.cjs.map +1 -0
- package/dist/cjs/define/handler.d.cts +13 -0
- package/dist/cjs/define/middleware.cjs +36 -0
- package/dist/cjs/define/middleware.cjs.map +1 -0
- package/dist/cjs/define/middleware.d.cts +85 -0
- package/dist/cjs/define/validators.cjs +14 -0
- package/dist/cjs/define/validators.cjs.map +1 -0
- package/dist/cjs/define/validators.d.cts +8 -0
- package/dist/cjs/factories.cjs +29 -0
- package/dist/cjs/factories.cjs.map +1 -0
- package/dist/cjs/factories.d.cts +61 -0
- package/dist/cjs/index.cjs +42 -0
- package/dist/cjs/index.d.cts +12 -0
- package/dist/cjs/middleware/auth.cjs +34 -0
- package/dist/cjs/middleware/auth.cjs.map +1 -0
- package/dist/cjs/middleware/auth.d.cts +9 -0
- package/dist/cjs/middleware/body-limit.cjs +12 -0
- package/dist/cjs/middleware/body-limit.cjs.map +1 -0
- package/dist/cjs/middleware/body-limit.d.cts +3 -0
- package/dist/cjs/middleware/compress.cjs +12 -0
- package/dist/cjs/middleware/compress.cjs.map +1 -0
- package/dist/cjs/middleware/compress.d.cts +3 -0
- package/dist/cjs/middleware/cors.cjs +12 -0
- package/dist/cjs/middleware/cors.cjs.map +1 -0
- package/dist/cjs/middleware/cors.d.cts +3 -0
- package/dist/cjs/middleware/csrf.cjs +12 -0
- package/dist/cjs/middleware/csrf.cjs.map +1 -0
- package/dist/cjs/middleware/csrf.d.cts +3 -0
- package/dist/cjs/middleware/etag.cjs +12 -0
- package/dist/cjs/middleware/etag.cjs.map +1 -0
- package/dist/cjs/middleware/etag.d.cts +3 -0
- package/dist/cjs/middleware/jwk.cjs +25 -0
- package/dist/cjs/middleware/jwk.cjs.map +1 -0
- package/dist/cjs/middleware/jwk.d.cts +15 -0
- package/dist/cjs/middleware/jwt.cjs +16 -0
- package/dist/cjs/middleware/jwt.cjs.map +1 -0
- package/dist/cjs/middleware/jwt.d.cts +10 -0
- package/dist/cjs/middleware/secure-headers.cjs +12 -0
- package/dist/cjs/middleware/secure-headers.cjs.map +1 -0
- package/dist/cjs/middleware/secure-headers.d.cts +3 -0
- package/dist/cjs/middleware/timing.cjs +12 -0
- package/dist/cjs/middleware/timing.cjs.map +1 -0
- package/dist/cjs/middleware/timing.d.cts +3 -0
- package/dist/cjs/middleware.cjs +17 -0
- package/dist/cjs/middleware.cjs.map +1 -0
- package/dist/cjs/middleware.d.cts +2 -0
- package/dist/cjs/register.d.cts +2 -0
- package/dist/cjs/route.cjs +94 -0
- package/dist/cjs/route.cjs.map +1 -0
- package/dist/cjs/route.d.cts +5 -0
- package/dist/cjs/taser-app.cjs +42 -0
- package/dist/cjs/taser-app.cjs.map +1 -0
- package/dist/cjs/taser-app.d.cts +21 -0
- package/dist/cjs/taser-router.cjs +83 -0
- package/dist/cjs/taser-router.cjs.map +1 -0
- package/dist/cjs/taser-router.d.cts +44 -0
- package/dist/cjs/types/app.d.cts +46 -0
- package/dist/cjs/types/index.d.cts +305 -0
- package/dist/cjs/types/returns.d.cts +37 -0
- package/dist/cjs/types/schema.d.cts +14 -0
- package/dist/cjs/types/type-utils.d.cts +52 -0
- package/dist/cjs/types/units.cjs +8 -0
- package/dist/cjs/types/units.cjs.map +1 -0
- package/dist/cjs/types/units.d.cts +98 -0
- package/dist/esm/constants.d.ts +8 -0
- package/dist/esm/constants.js +16 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/create-context.d.ts +5 -0
- package/dist/esm/create-context.js +8 -0
- package/dist/esm/create-context.js.map +1 -0
- package/dist/esm/define/handler.d.ts +13 -0
- package/dist/esm/define/handler.js +38 -0
- package/dist/esm/define/handler.js.map +1 -0
- package/dist/esm/define/middleware.d.ts +85 -0
- package/dist/esm/define/middleware.js +36 -0
- package/dist/esm/define/middleware.js.map +1 -0
- package/dist/esm/define/validators.d.ts +8 -0
- package/dist/esm/define/validators.js +14 -0
- package/dist/esm/define/validators.js.map +1 -0
- package/dist/esm/factories.d.ts +61 -0
- package/dist/esm/factories.js +21 -0
- package/dist/esm/factories.js.map +1 -0
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/middleware/auth.d.ts +9 -0
- package/dist/esm/middleware/auth.js +33 -0
- package/dist/esm/middleware/auth.js.map +1 -0
- package/dist/esm/middleware/body-limit.d.ts +3 -0
- package/dist/esm/middleware/body-limit.js +11 -0
- package/dist/esm/middleware/body-limit.js.map +1 -0
- package/dist/esm/middleware/compress.d.ts +3 -0
- package/dist/esm/middleware/compress.js +11 -0
- package/dist/esm/middleware/compress.js.map +1 -0
- package/dist/esm/middleware/cors.d.ts +3 -0
- package/dist/esm/middleware/cors.js +11 -0
- package/dist/esm/middleware/cors.js.map +1 -0
- package/dist/esm/middleware/csrf.d.ts +3 -0
- package/dist/esm/middleware/csrf.js +11 -0
- package/dist/esm/middleware/csrf.js.map +1 -0
- package/dist/esm/middleware/etag.d.ts +3 -0
- package/dist/esm/middleware/etag.js +11 -0
- package/dist/esm/middleware/etag.js.map +1 -0
- package/dist/esm/middleware/jwk.d.ts +15 -0
- package/dist/esm/middleware/jwk.js +24 -0
- package/dist/esm/middleware/jwk.js.map +1 -0
- package/dist/esm/middleware/jwt.d.ts +10 -0
- package/dist/esm/middleware/jwt.js +15 -0
- package/dist/esm/middleware/jwt.js.map +1 -0
- package/dist/esm/middleware/secure-headers.d.ts +3 -0
- package/dist/esm/middleware/secure-headers.js +11 -0
- package/dist/esm/middleware/secure-headers.js.map +1 -0
- package/dist/esm/middleware/timing.d.ts +3 -0
- package/dist/esm/middleware/timing.js +11 -0
- package/dist/esm/middleware/timing.js.map +1 -0
- package/dist/esm/middleware.d.ts +2 -0
- package/dist/esm/middleware.js +17 -0
- package/dist/esm/middleware.js.map +1 -0
- package/dist/esm/register.d.ts +2 -0
- package/dist/esm/route.d.ts +5 -0
- package/dist/esm/route.js +94 -0
- package/dist/esm/route.js.map +1 -0
- package/dist/esm/taser-app.d.ts +21 -0
- package/dist/esm/taser-app.js +40 -0
- package/dist/esm/taser-app.js.map +1 -0
- package/dist/esm/taser-router.d.ts +44 -0
- package/dist/esm/taser-router.js +82 -0
- package/dist/esm/taser-router.js.map +1 -0
- package/dist/esm/types/app.d.ts +46 -0
- package/dist/esm/types/index.d.ts +305 -0
- package/dist/esm/types/returns.d.ts +37 -0
- package/dist/esm/types/schema.d.ts +14 -0
- package/dist/esm/types/type-utils.d.ts +52 -0
- package/dist/esm/types/units.d.ts +98 -0
- package/dist/esm/types/units.js +8 -0
- package/dist/esm/types/units.js.map +1 -0
- package/package.json +149 -0
- package/src/constants.ts +10 -0
- package/src/create-context.ts +19 -0
- package/src/define/handler.ts +72 -0
- package/src/define/middleware.ts +289 -0
- package/src/define/validators.ts +22 -0
- package/src/factories.ts +183 -0
- package/src/index.ts +44 -0
- package/src/middleware/auth.ts +51 -0
- package/src/middleware/body-limit.ts +11 -0
- package/src/middleware/compress.ts +11 -0
- package/src/middleware/cors.ts +11 -0
- package/src/middleware/csrf.ts +11 -0
- package/src/middleware/etag.ts +11 -0
- package/src/middleware/jwk.ts +47 -0
- package/src/middleware/jwt.ts +18 -0
- package/src/middleware/secure-headers.ts +11 -0
- package/src/middleware/timing.ts +11 -0
- package/src/middleware.ts +19 -0
- package/src/register.ts +1 -0
- package/src/route.ts +145 -0
- package/src/taser-app.ts +43 -0
- package/src/taser-router.ts +160 -0
- package/src/types/app.ts +65 -0
- package/src/types/index.ts +1064 -0
- package/src/types/returns.ts +135 -0
- package/src/types/schema.ts +22 -0
- package/src/types/type-utils.ts +86 -0
- package/src/types/units.ts +167 -0
package/src/factories.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { createRouteBuilder } from './route.js'
|
|
2
|
+
import type { RouteBuilder, RoutePath, Schema } from './types/index.js'
|
|
3
|
+
import type { AppContext, HttpMethod } from './types/units.js'
|
|
4
|
+
|
|
5
|
+
type WithoutBodyOptions<TQuery, TParams, TQueryIn = unknown, TParamsIn = unknown> = {
|
|
6
|
+
query?: Schema<TQuery, TQueryIn>
|
|
7
|
+
params?: Schema<TParams, TParamsIn>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type WithBodyOptions<
|
|
11
|
+
TQuery,
|
|
12
|
+
TParams,
|
|
13
|
+
TBody,
|
|
14
|
+
TQueryIn = unknown,
|
|
15
|
+
TParamsIn = unknown,
|
|
16
|
+
TBodyIn = unknown,
|
|
17
|
+
> = WithoutBodyOptions<TQuery, TParams, TQueryIn, TParamsIn> & {
|
|
18
|
+
body?: Schema<TBody, TBodyIn>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type CreateWithoutBodyRoute<
|
|
22
|
+
M extends 'GET' | 'DELETE' | 'OPTIONS' | 'HEAD',
|
|
23
|
+
TAppContext extends Record<string, unknown> = AppContext,
|
|
24
|
+
> = {
|
|
25
|
+
<const Path extends RoutePath>(path: Path): RouteBuilder<Path, M, readonly [], {}, {}, TAppContext>
|
|
26
|
+
<
|
|
27
|
+
const Path extends RoutePath,
|
|
28
|
+
TQuery = unknown,
|
|
29
|
+
TParams = unknown,
|
|
30
|
+
TQueryIn = unknown,
|
|
31
|
+
TParamsIn = unknown,
|
|
32
|
+
>(
|
|
33
|
+
path: Path,
|
|
34
|
+
options: WithoutBodyOptions<TQuery, TParams, TQueryIn, TParamsIn>,
|
|
35
|
+
): RouteBuilder<
|
|
36
|
+
Path,
|
|
37
|
+
M,
|
|
38
|
+
readonly [],
|
|
39
|
+
{
|
|
40
|
+
query: TQuery
|
|
41
|
+
params: TParams
|
|
42
|
+
queryIn: TQueryIn
|
|
43
|
+
paramsIn: TParamsIn
|
|
44
|
+
},
|
|
45
|
+
{},
|
|
46
|
+
TAppContext
|
|
47
|
+
>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type CreateWithBodyRoute<
|
|
51
|
+
M extends 'POST' | 'PUT' | 'PATCH',
|
|
52
|
+
TAppContext extends Record<string, unknown> = AppContext,
|
|
53
|
+
> = {
|
|
54
|
+
<const Path extends RoutePath>(path: Path): RouteBuilder<Path, M, readonly [], {}, {}, TAppContext>
|
|
55
|
+
<
|
|
56
|
+
const Path extends RoutePath,
|
|
57
|
+
TQuery = unknown,
|
|
58
|
+
TParams = unknown,
|
|
59
|
+
TBody = unknown,
|
|
60
|
+
TQueryIn = unknown,
|
|
61
|
+
TParamsIn = unknown,
|
|
62
|
+
TBodyIn = unknown,
|
|
63
|
+
>(
|
|
64
|
+
path: Path,
|
|
65
|
+
options: WithBodyOptions<TQuery, TParams, TBody, TQueryIn, TParamsIn, TBodyIn>,
|
|
66
|
+
): RouteBuilder<
|
|
67
|
+
Path,
|
|
68
|
+
M,
|
|
69
|
+
readonly [],
|
|
70
|
+
{
|
|
71
|
+
query: TQuery
|
|
72
|
+
params: TParams
|
|
73
|
+
body: TBody
|
|
74
|
+
queryIn: TQueryIn
|
|
75
|
+
paramsIn: TParamsIn
|
|
76
|
+
bodyIn: TBodyIn
|
|
77
|
+
},
|
|
78
|
+
{},
|
|
79
|
+
TAppContext
|
|
80
|
+
>
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type CreateAnyRoute<TAppContext extends Record<string, unknown> = AppContext> = {
|
|
84
|
+
<const Path extends RoutePath, const Methods extends readonly HttpMethod[]>(
|
|
85
|
+
path: Path,
|
|
86
|
+
methods: Methods,
|
|
87
|
+
): RouteBuilder<Path, Methods[number], readonly [], {}, {}, TAppContext>
|
|
88
|
+
<
|
|
89
|
+
const Path extends RoutePath,
|
|
90
|
+
const Methods extends readonly HttpMethod[],
|
|
91
|
+
TQuery = unknown,
|
|
92
|
+
TParams = unknown,
|
|
93
|
+
TBody = unknown,
|
|
94
|
+
TQueryIn = unknown,
|
|
95
|
+
TParamsIn = unknown,
|
|
96
|
+
TBodyIn = unknown,
|
|
97
|
+
>(
|
|
98
|
+
path: Path,
|
|
99
|
+
methods: Methods,
|
|
100
|
+
options: WithBodyOptions<TQuery, TParams, TBody, TQueryIn, TParamsIn, TBodyIn>,
|
|
101
|
+
): RouteBuilder<
|
|
102
|
+
Path,
|
|
103
|
+
Methods[number],
|
|
104
|
+
readonly [],
|
|
105
|
+
{
|
|
106
|
+
query: TQuery
|
|
107
|
+
params: TParams
|
|
108
|
+
body: TBody
|
|
109
|
+
queryIn: TQueryIn
|
|
110
|
+
paramsIn: TParamsIn
|
|
111
|
+
bodyIn: TBodyIn
|
|
112
|
+
},
|
|
113
|
+
{},
|
|
114
|
+
TAppContext
|
|
115
|
+
>
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type CreateAllRoute<TAppContext extends Record<string, unknown> = AppContext> = {
|
|
119
|
+
<const Path extends RoutePath>(path: Path): RouteBuilder<Path, HttpMethod, readonly [], {}, {}, TAppContext>
|
|
120
|
+
<
|
|
121
|
+
const Path extends RoutePath,
|
|
122
|
+
TQuery = unknown,
|
|
123
|
+
TParams = unknown,
|
|
124
|
+
TBody = unknown,
|
|
125
|
+
TQueryIn = unknown,
|
|
126
|
+
TParamsIn = unknown,
|
|
127
|
+
TBodyIn = unknown,
|
|
128
|
+
>(
|
|
129
|
+
path: Path,
|
|
130
|
+
options: WithBodyOptions<TQuery, TParams, TBody, TQueryIn, TParamsIn, TBodyIn>,
|
|
131
|
+
): RouteBuilder<
|
|
132
|
+
Path,
|
|
133
|
+
HttpMethod,
|
|
134
|
+
readonly [],
|
|
135
|
+
{
|
|
136
|
+
query: TQuery
|
|
137
|
+
params: TParams
|
|
138
|
+
body: TBody
|
|
139
|
+
queryIn: TQueryIn
|
|
140
|
+
paramsIn: TParamsIn
|
|
141
|
+
bodyIn: TBodyIn
|
|
142
|
+
},
|
|
143
|
+
{},
|
|
144
|
+
TAppContext
|
|
145
|
+
>
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function createWithoutBodyRoute<M extends 'GET' | 'DELETE' | 'OPTIONS' | 'HEAD'>(
|
|
149
|
+
method: M,
|
|
150
|
+
): CreateWithoutBodyRoute<M> {
|
|
151
|
+
return ((path: string, options?: WithoutBodyOptions<unknown, unknown>) =>
|
|
152
|
+
createRouteBuilder(path, method, options)
|
|
153
|
+
) as unknown as CreateWithoutBodyRoute<M>
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function createWithBodyRoute<M extends 'POST' | 'PUT' | 'PATCH'>(
|
|
157
|
+
method: M,
|
|
158
|
+
): CreateWithBodyRoute<M> {
|
|
159
|
+
return ((path: string, options?: WithBodyOptions<unknown, unknown, unknown>) =>
|
|
160
|
+
createRouteBuilder(path, method, options)
|
|
161
|
+
) as unknown as CreateWithBodyRoute<M>
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const createGetRoute = createWithoutBodyRoute('GET')
|
|
165
|
+
export const createDeleteRoute = createWithoutBodyRoute('DELETE')
|
|
166
|
+
export const createOptionsRoute = createWithoutBodyRoute('OPTIONS')
|
|
167
|
+
export const createHeadRoute = createWithoutBodyRoute('HEAD')
|
|
168
|
+
export const createPostRoute = createWithBodyRoute('POST')
|
|
169
|
+
export const createPutRoute = createWithBodyRoute('PUT')
|
|
170
|
+
export const createPatchRoute = createWithBodyRoute('PATCH')
|
|
171
|
+
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
173
|
+
export const createAnyRoute: CreateAnyRoute = ((
|
|
174
|
+
path: string,
|
|
175
|
+
methods: readonly HttpMethod[],
|
|
176
|
+
options?: WithBodyOptions<unknown, unknown, unknown>,
|
|
177
|
+
) => createRouteBuilder(path, 'ANY', options, methods)) as unknown as CreateAnyRoute
|
|
178
|
+
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
180
|
+
export const createAllRoute: CreateAllRoute = ((
|
|
181
|
+
path: string,
|
|
182
|
+
options?: WithBodyOptions<unknown, unknown, unknown>,
|
|
183
|
+
) => createRouteBuilder(path, 'ALL', options)) as unknown as CreateAllRoute
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type { RouterRegister } from './register.js'
|
|
2
|
+
export type {
|
|
3
|
+
InferInput,
|
|
4
|
+
InferOutput,
|
|
5
|
+
Method,
|
|
6
|
+
PathParams,
|
|
7
|
+
ReturnsMap,
|
|
8
|
+
RoutePath,
|
|
9
|
+
Schema,
|
|
10
|
+
Simplify,
|
|
11
|
+
} from './types/index.js'
|
|
12
|
+
export type {
|
|
13
|
+
ContextDefinition,
|
|
14
|
+
CreateContextArgs,
|
|
15
|
+
CreateTaserAppOptions,
|
|
16
|
+
InferAppContext,
|
|
17
|
+
InferAppManifest,
|
|
18
|
+
OnErrorOptions,
|
|
19
|
+
RouteManifestShape,
|
|
20
|
+
TaserHandler,
|
|
21
|
+
} from './types/app.js'
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
isReplyResult,
|
|
25
|
+
reply,
|
|
26
|
+
ValidationError,
|
|
27
|
+
validationErrorSchema,
|
|
28
|
+
} from '@taserjs/router-utils'
|
|
29
|
+
export type {
|
|
30
|
+
ReplyBodyKind,
|
|
31
|
+
ReplyOf,
|
|
32
|
+
ResponseValidationFailureHandler,
|
|
33
|
+
SuccessReplyData,
|
|
34
|
+
SuccessStatusCode,
|
|
35
|
+
} from '@taserjs/router-utils'
|
|
36
|
+
|
|
37
|
+
export { createAnyRoute, createAllRoute } from './factories.js'
|
|
38
|
+
export { createTaserApp, TaserRouter } from './taser-router.js'
|
|
39
|
+
export { TaserApp, TaserMountedApp, TaserNativeBound } from './taser-app.js'
|
|
40
|
+
export { createContext } from './create-context.js'
|
|
41
|
+
export { defineHandler } from './define/handler.js'
|
|
42
|
+
export { defineMiddleware } from './define/middleware.js'
|
|
43
|
+
|
|
44
|
+
export type { TaserCookieJar, TaserHeaders } from '@taserjs/router-core'
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createTaserCompatHandler } from '@taserjs/router-core'
|
|
2
|
+
import { validateSchema, ValidationError } from '@taserjs/router-utils'
|
|
3
|
+
import type { MiddlewareHandler } from 'hono'
|
|
4
|
+
|
|
5
|
+
import { defineMiddleware } from '../define/middleware.js'
|
|
6
|
+
import type { InferOutput, Schema } from '../types/schema.js'
|
|
7
|
+
import type { MiddlewareReturnFromParts, MiddlewareUnit } from '../types/units.js'
|
|
8
|
+
|
|
9
|
+
export function wrapHonoMiddleware<F extends (...args: never[]) => MiddlewareHandler>(
|
|
10
|
+
honoFactory: F,
|
|
11
|
+
): (...args: Parameters<F>) => MiddlewareUnit<MiddlewareReturnFromParts<unknown, unknown, unknown, {}>> {
|
|
12
|
+
return (...args) => defineMiddleware(honoFactory(...args))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type JwtPayloadState<TPayload> = {
|
|
16
|
+
jwtPayload: TPayload
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type AuthMiddlewareUnit<TPayload> = MiddlewareUnit<
|
|
20
|
+
MiddlewareReturnFromParts<unknown, unknown, unknown, JwtPayloadState<TPayload>>
|
|
21
|
+
>
|
|
22
|
+
|
|
23
|
+
function asJwtPayloadStateSchema<TPayload>(
|
|
24
|
+
payloadSchema: Schema<TPayload>,
|
|
25
|
+
): Schema<JwtPayloadState<InferOutput<Schema<TPayload>>>> {
|
|
26
|
+
return payloadSchema as unknown as Schema<JwtPayloadState<InferOutput<Schema<TPayload>>>>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function createAuthMiddleware<TPayload>(
|
|
30
|
+
payloadSchema: Schema<TPayload>,
|
|
31
|
+
honoMw: MiddlewareHandler,
|
|
32
|
+
): AuthMiddlewareUnit<InferOutput<Schema<TPayload>>> {
|
|
33
|
+
return defineMiddleware({
|
|
34
|
+
state: asJwtPayloadStateSchema(payloadSchema),
|
|
35
|
+
handler: (ctx, next) => {
|
|
36
|
+
return createTaserCompatHandler(honoMw)(ctx, async () => {
|
|
37
|
+
const payload = (ctx.var as { jwtPayload?: unknown }).jwtPayload
|
|
38
|
+
try {
|
|
39
|
+
const validated = await validateSchema(payloadSchema, payload)
|
|
40
|
+
return next({ state: { jwtPayload: validated } })
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error instanceof ValidationError) {
|
|
44
|
+
return ctx.reply.forbidden({ error: 'Forbidden', issues: error.issues })
|
|
45
|
+
}
|
|
46
|
+
throw error
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { bodyLimit as honoBodyLimit } from 'hono/body-limit'
|
|
2
|
+
|
|
3
|
+
import { wrapHonoMiddleware } from './auth.js'
|
|
4
|
+
|
|
5
|
+
const honoBodyLimitMiddleware = wrapHonoMiddleware(honoBodyLimit)
|
|
6
|
+
|
|
7
|
+
export function bodyLimit(...args: Parameters<typeof honoBodyLimit>) {
|
|
8
|
+
return honoBodyLimitMiddleware(...args)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type BodyLimitOptions = Parameters<typeof honoBodyLimit>[0]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { compress as honoCompress } from 'hono/compress'
|
|
2
|
+
|
|
3
|
+
import { wrapHonoMiddleware } from './auth.js'
|
|
4
|
+
|
|
5
|
+
const honoCompressMiddleware = wrapHonoMiddleware(honoCompress)
|
|
6
|
+
|
|
7
|
+
export function compress(...args: Parameters<typeof honoCompress>) {
|
|
8
|
+
return honoCompressMiddleware(...args)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type CompressOptions = NonNullable<Parameters<typeof honoCompress>[0]>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { cors as honoCors } from 'hono/cors'
|
|
2
|
+
|
|
3
|
+
import { wrapHonoMiddleware } from './auth.js'
|
|
4
|
+
|
|
5
|
+
const honoCorsMiddleware = wrapHonoMiddleware(honoCors)
|
|
6
|
+
|
|
7
|
+
export function cors(...args: Parameters<typeof honoCors>) {
|
|
8
|
+
return honoCorsMiddleware(...args)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type CorsOptions = NonNullable<Parameters<typeof honoCors>[0]>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { csrf as honoCsrf } from 'hono/csrf'
|
|
2
|
+
|
|
3
|
+
import { wrapHonoMiddleware } from './auth.js'
|
|
4
|
+
|
|
5
|
+
const honoCsrfMiddleware = wrapHonoMiddleware(honoCsrf)
|
|
6
|
+
|
|
7
|
+
export function csrf(...args: Parameters<typeof honoCsrf>) {
|
|
8
|
+
return honoCsrfMiddleware(...args)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type CsrfOptions = NonNullable<Parameters<typeof honoCsrf>[0]>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { etag as honoEtag } from 'hono/etag'
|
|
2
|
+
|
|
3
|
+
import { wrapHonoMiddleware } from './auth.js'
|
|
4
|
+
|
|
5
|
+
const honoEtagMiddleware = wrapHonoMiddleware(honoEtag)
|
|
6
|
+
|
|
7
|
+
export function etag(...args: Parameters<typeof honoEtag>) {
|
|
8
|
+
return honoEtagMiddleware(...args)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type EtagOptions = NonNullable<Parameters<typeof honoEtag>[0]>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jwk as honoJwk } from 'hono/jwk'
|
|
2
|
+
|
|
3
|
+
import { createAuthMiddleware, type AuthMiddlewareUnit } from './auth.js'
|
|
4
|
+
import type { InferOutput, Schema } from '../types/schema.js'
|
|
5
|
+
|
|
6
|
+
export type JwkOptions = Parameters<typeof honoJwk>[0]
|
|
7
|
+
|
|
8
|
+
export type JwkRequestInit = Pick<RequestInit, 'headers'>
|
|
9
|
+
|
|
10
|
+
export type JwkMiddlewareOptions = JwkOptions & {
|
|
11
|
+
/** Allow `http://` JWKS URLs (local dev). Default false — requires `https://`. */
|
|
12
|
+
allowInsecure?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function assertJwksScheme(jwksUri: string, allowInsecure: boolean): void {
|
|
16
|
+
const scheme = new URL(jwksUri).protocol.replace(':', '')
|
|
17
|
+
if (scheme === 'https') {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
if (scheme === 'http' && allowInsecure) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
throw new Error(
|
|
24
|
+
`JWKS URL must use https:// (or http:// with allowInsecure: true): "${jwksUri}"`,
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* JWK auth middleware. Invalid or missing tokens return **401** (Hono).
|
|
30
|
+
* Valid tokens whose payload fails `payloadSchema` return **403**.
|
|
31
|
+
* Static `jwks_uri` must use HTTPS unless `allowInsecure: true`.
|
|
32
|
+
*/
|
|
33
|
+
export function jwk<TPayload>(
|
|
34
|
+
payloadSchema: Schema<TPayload>,
|
|
35
|
+
options: JwkMiddlewareOptions,
|
|
36
|
+
init?: JwkRequestInit,
|
|
37
|
+
): AuthMiddlewareUnit<InferOutput<Schema<TPayload>>> {
|
|
38
|
+
const jwksUri = options.jwks_uri
|
|
39
|
+
if (typeof jwksUri === 'string') {
|
|
40
|
+
assertJwksScheme(jwksUri, options.allowInsecure ?? false)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { allowInsecure: _allowInsecure, ...honoOptions } = options
|
|
44
|
+
const safeInit = init?.headers !== undefined ? { headers: init.headers } : undefined
|
|
45
|
+
|
|
46
|
+
return createAuthMiddleware(payloadSchema, honoJwk(honoOptions, safeInit))
|
|
47
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jwt as honoJwt } from 'hono/jwt'
|
|
2
|
+
|
|
3
|
+
import { createAuthMiddleware, type AuthMiddlewareUnit } from './auth.js'
|
|
4
|
+
import type { InferOutput, Schema } from '../types/schema.js'
|
|
5
|
+
|
|
6
|
+
export type JwtOptions = Parameters<typeof honoJwt>[0]
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* JWT auth middleware. Invalid or missing tokens return **401** (Hono).
|
|
10
|
+
* Valid tokens whose payload fails `payloadSchema` return **403**.
|
|
11
|
+
* Use optional schema fields for intentionally optional claims.
|
|
12
|
+
*/
|
|
13
|
+
export function jwt<TPayload>(
|
|
14
|
+
payloadSchema: Schema<TPayload>,
|
|
15
|
+
options: JwtOptions,
|
|
16
|
+
): AuthMiddlewareUnit<InferOutput<Schema<TPayload>>> {
|
|
17
|
+
return createAuthMiddleware(payloadSchema, honoJwt(options))
|
|
18
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { secureHeaders as honoSecureHeaders } from 'hono/secure-headers'
|
|
2
|
+
|
|
3
|
+
import { wrapHonoMiddleware } from './auth.js'
|
|
4
|
+
|
|
5
|
+
const honoSecureHeadersMiddleware = wrapHonoMiddleware(honoSecureHeaders)
|
|
6
|
+
|
|
7
|
+
export function secureHeaders(...args: Parameters<typeof honoSecureHeaders>) {
|
|
8
|
+
return honoSecureHeadersMiddleware(...args)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type SecureHeadersOptions = NonNullable<Parameters<typeof honoSecureHeaders>[0]>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { timing as honoTiming } from 'hono/timing'
|
|
2
|
+
|
|
3
|
+
import { wrapHonoMiddleware } from './auth.js'
|
|
4
|
+
|
|
5
|
+
const honoTimingMiddleware = wrapHonoMiddleware(honoTiming)
|
|
6
|
+
|
|
7
|
+
export function timing(...args: Parameters<typeof honoTiming>) {
|
|
8
|
+
return honoTimingMiddleware(...args)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type TimingOptions = NonNullable<Parameters<typeof honoTiming>[0]>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { LayoutId, MiddlewareBuilder } from './types/index.js'
|
|
2
|
+
import type { MiddlewareDefinition } from './types/units.js'
|
|
3
|
+
|
|
4
|
+
export function createMiddleware<const Layout extends LayoutId>(
|
|
5
|
+
layout: Layout,
|
|
6
|
+
): MiddlewareBuilder<Layout, readonly []> {
|
|
7
|
+
const entries: MiddlewareDefinition[] = []
|
|
8
|
+
|
|
9
|
+
const chain = {
|
|
10
|
+
layout,
|
|
11
|
+
middlewares: entries,
|
|
12
|
+
use(definition: MiddlewareDefinition) {
|
|
13
|
+
entries.push(definition)
|
|
14
|
+
return chain
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return chain as unknown as MiddlewareBuilder<Layout, readonly []>
|
|
19
|
+
}
|
package/src/register.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export interface RouterRegister {}
|
package/src/route.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec'
|
|
2
|
+
import {
|
|
3
|
+
collectReturnsFromDefinitions,
|
|
4
|
+
hasInputSchemas,
|
|
5
|
+
mergeReturnsMaps,
|
|
6
|
+
withAuto422,
|
|
7
|
+
} from '@taserjs/router-utils'
|
|
8
|
+
|
|
9
|
+
import type { Method, RouteBuilder, RoutePath, ReturnsMap, ValidatorParts } from './types/index.js'
|
|
10
|
+
import type { HttpMethod, MiddlewareDefinition } from './types/units.js'
|
|
11
|
+
import { isHandlerUnit } from './types/units.js'
|
|
12
|
+
import { HANDLER_SCHEMA_KEY_MAP } from './constants.js'
|
|
13
|
+
import {
|
|
14
|
+
pickDefinedSchemas,
|
|
15
|
+
type SchemaValidators,
|
|
16
|
+
} from './define/validators.js'
|
|
17
|
+
|
|
18
|
+
function toUtilsMap(map: ReturnsMap | undefined): Record<number, StandardSchemaV1> {
|
|
19
|
+
if (!map) {
|
|
20
|
+
return {}
|
|
21
|
+
}
|
|
22
|
+
const out: Record<number, StandardSchemaV1> = {}
|
|
23
|
+
for (const [key, schema] of Object.entries(map)) {
|
|
24
|
+
if (schema !== undefined) {
|
|
25
|
+
out[Number(key)] = schema
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return out
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function buildEffectiveReturns(args: {
|
|
32
|
+
middlewareReturns: ReturnsMap
|
|
33
|
+
routeReturns: ReturnsMap
|
|
34
|
+
handlerMiddlewareReturns: ReturnsMap
|
|
35
|
+
handlerReturns: ReturnsMap | undefined
|
|
36
|
+
schemas: {
|
|
37
|
+
query?: unknown
|
|
38
|
+
params?: unknown
|
|
39
|
+
body?: unknown
|
|
40
|
+
handlerQuery?: unknown
|
|
41
|
+
handlerParams?: unknown
|
|
42
|
+
handlerBody?: unknown
|
|
43
|
+
middlewares?: readonly MiddlewareDefinition[]
|
|
44
|
+
handlerMiddlewares?: readonly MiddlewareDefinition[]
|
|
45
|
+
}
|
|
46
|
+
}): Record<number, StandardSchemaV1> | undefined {
|
|
47
|
+
const merged = mergeReturnsMaps(
|
|
48
|
+
toUtilsMap(args.middlewareReturns),
|
|
49
|
+
toUtilsMap(args.routeReturns),
|
|
50
|
+
toUtilsMap(args.handlerMiddlewareReturns),
|
|
51
|
+
toUtilsMap(args.handlerReturns),
|
|
52
|
+
)
|
|
53
|
+
const with422 = withAuto422(merged, hasInputSchemas(args.schemas))
|
|
54
|
+
return Object.keys(with422).length > 0 ? with422 : undefined
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function buildRouteBase(
|
|
58
|
+
path: string,
|
|
59
|
+
method: HttpMethod | 'ANY' | 'ALL',
|
|
60
|
+
methods: readonly HttpMethod[] | undefined,
|
|
61
|
+
middlewares: MiddlewareDefinition[],
|
|
62
|
+
) {
|
|
63
|
+
return {
|
|
64
|
+
path,
|
|
65
|
+
method,
|
|
66
|
+
...(methods ? { methods: [...methods] } : {}),
|
|
67
|
+
middlewares: [...middlewares],
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Shared internal builder — not part of the public `@taserjs/router` API. */
|
|
72
|
+
export function createRouteBuilder(
|
|
73
|
+
path: string,
|
|
74
|
+
method: HttpMethod | 'ANY' | 'ALL',
|
|
75
|
+
validators: SchemaValidators = {},
|
|
76
|
+
methods?: readonly HttpMethod[],
|
|
77
|
+
): RouteBuilder<RoutePath, Method, readonly [], ValidatorParts> {
|
|
78
|
+
const middlewares: MiddlewareDefinition[] = []
|
|
79
|
+
let routeReturns: Record<number, StandardSchemaV1> = {}
|
|
80
|
+
|
|
81
|
+
const builder = {
|
|
82
|
+
path,
|
|
83
|
+
method,
|
|
84
|
+
returns(map: ReturnsMap) {
|
|
85
|
+
routeReturns = { ...routeReturns, ...toUtilsMap(map) }
|
|
86
|
+
return builder
|
|
87
|
+
},
|
|
88
|
+
use(definition: MiddlewareDefinition) {
|
|
89
|
+
middlewares.push(definition)
|
|
90
|
+
return builder
|
|
91
|
+
},
|
|
92
|
+
handler(fnOrUnit: ((ctx: unknown) => unknown) | unknown) {
|
|
93
|
+
const routeSchemas = pickDefinedSchemas(validators)
|
|
94
|
+
const base = buildRouteBase(path, method, methods, middlewares)
|
|
95
|
+
|
|
96
|
+
if (isHandlerUnit(fnOrUnit)) {
|
|
97
|
+
const handlerSchemas = pickDefinedSchemas(fnOrUnit, HANDLER_SCHEMA_KEY_MAP)
|
|
98
|
+
const returns = buildEffectiveReturns({
|
|
99
|
+
middlewareReturns: collectReturnsFromDefinitions(middlewares),
|
|
100
|
+
routeReturns: routeReturns,
|
|
101
|
+
handlerMiddlewareReturns: collectReturnsFromDefinitions(fnOrUnit.middlewares),
|
|
102
|
+
handlerReturns: fnOrUnit.returns,
|
|
103
|
+
schemas: {
|
|
104
|
+
...validators,
|
|
105
|
+
handlerQuery: fnOrUnit.query,
|
|
106
|
+
handlerParams: fnOrUnit.params,
|
|
107
|
+
handlerBody: fnOrUnit.body,
|
|
108
|
+
middlewares,
|
|
109
|
+
handlerMiddlewares: fnOrUnit.middlewares,
|
|
110
|
+
},
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
...base,
|
|
115
|
+
handlerMiddlewares: [...fnOrUnit.middlewares],
|
|
116
|
+
handler: fnOrUnit.handler,
|
|
117
|
+
...routeSchemas,
|
|
118
|
+
...handlerSchemas,
|
|
119
|
+
...(returns ? { returns } : {}),
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const returns = buildEffectiveReturns({
|
|
124
|
+
middlewareReturns: collectReturnsFromDefinitions(middlewares),
|
|
125
|
+
routeReturns: routeReturns,
|
|
126
|
+
handlerMiddlewareReturns: {},
|
|
127
|
+
handlerReturns: undefined,
|
|
128
|
+
schemas: {
|
|
129
|
+
...validators,
|
|
130
|
+
middlewares,
|
|
131
|
+
},
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
...base,
|
|
136
|
+
handlerMiddlewares: [],
|
|
137
|
+
handler: fnOrUnit as (ctx: unknown) => Response | Promise<Response>,
|
|
138
|
+
...routeSchemas,
|
|
139
|
+
...(returns ? { returns } : {}),
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return builder as unknown as RouteBuilder<RoutePath, Method, readonly [], ValidatorParts>
|
|
145
|
+
}
|
package/src/taser-app.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { TaserRuntime } from '@taserjs/router-core'
|
|
2
|
+
import type { RouteManifestShape } from '@taserjs/router-core'
|
|
3
|
+
|
|
4
|
+
class TaserServeView {
|
|
5
|
+
constructor(protected readonly runtime: TaserRuntime) { }
|
|
6
|
+
|
|
7
|
+
fetch(request: Request, env?: unknown, executionCtx?: unknown): Promise<Response> {
|
|
8
|
+
return this.runtime.fetch(request, env, executionCtx as never)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
native(native: unknown): TaserNativeBound {
|
|
12
|
+
return new TaserNativeBound(this.runtime, native)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class TaserNativeBound {
|
|
17
|
+
constructor(
|
|
18
|
+
private readonly runtime: TaserRuntime,
|
|
19
|
+
private readonly boundNative: unknown,
|
|
20
|
+
) { }
|
|
21
|
+
|
|
22
|
+
fetch(request: Request, env?: unknown, executionCtx?: unknown): Promise<Response> {
|
|
23
|
+
return this.runtime.native(this.boundNative).fetch(request, env, executionCtx as never)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class TaserMountedApp extends TaserServeView { }
|
|
28
|
+
|
|
29
|
+
export class TaserApp<TManifest extends RouteManifestShape = RouteManifestShape> extends TaserServeView {
|
|
30
|
+
readonly __manifest?: TManifest
|
|
31
|
+
|
|
32
|
+
constructor(runtime: TaserRuntime, manifest?: TManifest) {
|
|
33
|
+
super(runtime)
|
|
34
|
+
if (manifest !== undefined) {
|
|
35
|
+
this.__manifest = manifest
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
base(prefix: string): TaserMountedApp {
|
|
40
|
+
this.runtime.registerRoutePrefix(prefix)
|
|
41
|
+
return new TaserMountedApp(this.runtime)
|
|
42
|
+
}
|
|
43
|
+
}
|