@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.
Files changed (173) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +24 -0
  3. package/dist/cjs/constants.cjs +17 -0
  4. package/dist/cjs/constants.cjs.map +1 -0
  5. package/dist/cjs/constants.d.cts +8 -0
  6. package/dist/cjs/create-context.cjs +8 -0
  7. package/dist/cjs/create-context.cjs.map +1 -0
  8. package/dist/cjs/create-context.d.cts +5 -0
  9. package/dist/cjs/define/handler.cjs +38 -0
  10. package/dist/cjs/define/handler.cjs.map +1 -0
  11. package/dist/cjs/define/handler.d.cts +13 -0
  12. package/dist/cjs/define/middleware.cjs +36 -0
  13. package/dist/cjs/define/middleware.cjs.map +1 -0
  14. package/dist/cjs/define/middleware.d.cts +85 -0
  15. package/dist/cjs/define/validators.cjs +14 -0
  16. package/dist/cjs/define/validators.cjs.map +1 -0
  17. package/dist/cjs/define/validators.d.cts +8 -0
  18. package/dist/cjs/factories.cjs +29 -0
  19. package/dist/cjs/factories.cjs.map +1 -0
  20. package/dist/cjs/factories.d.cts +61 -0
  21. package/dist/cjs/index.cjs +42 -0
  22. package/dist/cjs/index.d.cts +12 -0
  23. package/dist/cjs/middleware/auth.cjs +34 -0
  24. package/dist/cjs/middleware/auth.cjs.map +1 -0
  25. package/dist/cjs/middleware/auth.d.cts +9 -0
  26. package/dist/cjs/middleware/body-limit.cjs +12 -0
  27. package/dist/cjs/middleware/body-limit.cjs.map +1 -0
  28. package/dist/cjs/middleware/body-limit.d.cts +3 -0
  29. package/dist/cjs/middleware/compress.cjs +12 -0
  30. package/dist/cjs/middleware/compress.cjs.map +1 -0
  31. package/dist/cjs/middleware/compress.d.cts +3 -0
  32. package/dist/cjs/middleware/cors.cjs +12 -0
  33. package/dist/cjs/middleware/cors.cjs.map +1 -0
  34. package/dist/cjs/middleware/cors.d.cts +3 -0
  35. package/dist/cjs/middleware/csrf.cjs +12 -0
  36. package/dist/cjs/middleware/csrf.cjs.map +1 -0
  37. package/dist/cjs/middleware/csrf.d.cts +3 -0
  38. package/dist/cjs/middleware/etag.cjs +12 -0
  39. package/dist/cjs/middleware/etag.cjs.map +1 -0
  40. package/dist/cjs/middleware/etag.d.cts +3 -0
  41. package/dist/cjs/middleware/jwk.cjs +25 -0
  42. package/dist/cjs/middleware/jwk.cjs.map +1 -0
  43. package/dist/cjs/middleware/jwk.d.cts +15 -0
  44. package/dist/cjs/middleware/jwt.cjs +16 -0
  45. package/dist/cjs/middleware/jwt.cjs.map +1 -0
  46. package/dist/cjs/middleware/jwt.d.cts +10 -0
  47. package/dist/cjs/middleware/secure-headers.cjs +12 -0
  48. package/dist/cjs/middleware/secure-headers.cjs.map +1 -0
  49. package/dist/cjs/middleware/secure-headers.d.cts +3 -0
  50. package/dist/cjs/middleware/timing.cjs +12 -0
  51. package/dist/cjs/middleware/timing.cjs.map +1 -0
  52. package/dist/cjs/middleware/timing.d.cts +3 -0
  53. package/dist/cjs/middleware.cjs +17 -0
  54. package/dist/cjs/middleware.cjs.map +1 -0
  55. package/dist/cjs/middleware.d.cts +2 -0
  56. package/dist/cjs/register.d.cts +2 -0
  57. package/dist/cjs/route.cjs +94 -0
  58. package/dist/cjs/route.cjs.map +1 -0
  59. package/dist/cjs/route.d.cts +5 -0
  60. package/dist/cjs/taser-app.cjs +42 -0
  61. package/dist/cjs/taser-app.cjs.map +1 -0
  62. package/dist/cjs/taser-app.d.cts +21 -0
  63. package/dist/cjs/taser-router.cjs +83 -0
  64. package/dist/cjs/taser-router.cjs.map +1 -0
  65. package/dist/cjs/taser-router.d.cts +44 -0
  66. package/dist/cjs/types/app.d.cts +46 -0
  67. package/dist/cjs/types/index.d.cts +305 -0
  68. package/dist/cjs/types/returns.d.cts +37 -0
  69. package/dist/cjs/types/schema.d.cts +14 -0
  70. package/dist/cjs/types/type-utils.d.cts +52 -0
  71. package/dist/cjs/types/units.cjs +8 -0
  72. package/dist/cjs/types/units.cjs.map +1 -0
  73. package/dist/cjs/types/units.d.cts +98 -0
  74. package/dist/esm/constants.d.ts +8 -0
  75. package/dist/esm/constants.js +16 -0
  76. package/dist/esm/constants.js.map +1 -0
  77. package/dist/esm/create-context.d.ts +5 -0
  78. package/dist/esm/create-context.js +8 -0
  79. package/dist/esm/create-context.js.map +1 -0
  80. package/dist/esm/define/handler.d.ts +13 -0
  81. package/dist/esm/define/handler.js +38 -0
  82. package/dist/esm/define/handler.js.map +1 -0
  83. package/dist/esm/define/middleware.d.ts +85 -0
  84. package/dist/esm/define/middleware.js +36 -0
  85. package/dist/esm/define/middleware.js.map +1 -0
  86. package/dist/esm/define/validators.d.ts +8 -0
  87. package/dist/esm/define/validators.js +14 -0
  88. package/dist/esm/define/validators.js.map +1 -0
  89. package/dist/esm/factories.d.ts +61 -0
  90. package/dist/esm/factories.js +21 -0
  91. package/dist/esm/factories.js.map +1 -0
  92. package/dist/esm/index.d.ts +12 -0
  93. package/dist/esm/index.js +8 -0
  94. package/dist/esm/middleware/auth.d.ts +9 -0
  95. package/dist/esm/middleware/auth.js +33 -0
  96. package/dist/esm/middleware/auth.js.map +1 -0
  97. package/dist/esm/middleware/body-limit.d.ts +3 -0
  98. package/dist/esm/middleware/body-limit.js +11 -0
  99. package/dist/esm/middleware/body-limit.js.map +1 -0
  100. package/dist/esm/middleware/compress.d.ts +3 -0
  101. package/dist/esm/middleware/compress.js +11 -0
  102. package/dist/esm/middleware/compress.js.map +1 -0
  103. package/dist/esm/middleware/cors.d.ts +3 -0
  104. package/dist/esm/middleware/cors.js +11 -0
  105. package/dist/esm/middleware/cors.js.map +1 -0
  106. package/dist/esm/middleware/csrf.d.ts +3 -0
  107. package/dist/esm/middleware/csrf.js +11 -0
  108. package/dist/esm/middleware/csrf.js.map +1 -0
  109. package/dist/esm/middleware/etag.d.ts +3 -0
  110. package/dist/esm/middleware/etag.js +11 -0
  111. package/dist/esm/middleware/etag.js.map +1 -0
  112. package/dist/esm/middleware/jwk.d.ts +15 -0
  113. package/dist/esm/middleware/jwk.js +24 -0
  114. package/dist/esm/middleware/jwk.js.map +1 -0
  115. package/dist/esm/middleware/jwt.d.ts +10 -0
  116. package/dist/esm/middleware/jwt.js +15 -0
  117. package/dist/esm/middleware/jwt.js.map +1 -0
  118. package/dist/esm/middleware/secure-headers.d.ts +3 -0
  119. package/dist/esm/middleware/secure-headers.js +11 -0
  120. package/dist/esm/middleware/secure-headers.js.map +1 -0
  121. package/dist/esm/middleware/timing.d.ts +3 -0
  122. package/dist/esm/middleware/timing.js +11 -0
  123. package/dist/esm/middleware/timing.js.map +1 -0
  124. package/dist/esm/middleware.d.ts +2 -0
  125. package/dist/esm/middleware.js +17 -0
  126. package/dist/esm/middleware.js.map +1 -0
  127. package/dist/esm/register.d.ts +2 -0
  128. package/dist/esm/route.d.ts +5 -0
  129. package/dist/esm/route.js +94 -0
  130. package/dist/esm/route.js.map +1 -0
  131. package/dist/esm/taser-app.d.ts +21 -0
  132. package/dist/esm/taser-app.js +40 -0
  133. package/dist/esm/taser-app.js.map +1 -0
  134. package/dist/esm/taser-router.d.ts +44 -0
  135. package/dist/esm/taser-router.js +82 -0
  136. package/dist/esm/taser-router.js.map +1 -0
  137. package/dist/esm/types/app.d.ts +46 -0
  138. package/dist/esm/types/index.d.ts +305 -0
  139. package/dist/esm/types/returns.d.ts +37 -0
  140. package/dist/esm/types/schema.d.ts +14 -0
  141. package/dist/esm/types/type-utils.d.ts +52 -0
  142. package/dist/esm/types/units.d.ts +98 -0
  143. package/dist/esm/types/units.js +8 -0
  144. package/dist/esm/types/units.js.map +1 -0
  145. package/package.json +149 -0
  146. package/src/constants.ts +10 -0
  147. package/src/create-context.ts +19 -0
  148. package/src/define/handler.ts +72 -0
  149. package/src/define/middleware.ts +289 -0
  150. package/src/define/validators.ts +22 -0
  151. package/src/factories.ts +183 -0
  152. package/src/index.ts +44 -0
  153. package/src/middleware/auth.ts +51 -0
  154. package/src/middleware/body-limit.ts +11 -0
  155. package/src/middleware/compress.ts +11 -0
  156. package/src/middleware/cors.ts +11 -0
  157. package/src/middleware/csrf.ts +11 -0
  158. package/src/middleware/etag.ts +11 -0
  159. package/src/middleware/jwk.ts +47 -0
  160. package/src/middleware/jwt.ts +18 -0
  161. package/src/middleware/secure-headers.ts +11 -0
  162. package/src/middleware/timing.ts +11 -0
  163. package/src/middleware.ts +19 -0
  164. package/src/register.ts +1 -0
  165. package/src/route.ts +145 -0
  166. package/src/taser-app.ts +43 -0
  167. package/src/taser-router.ts +160 -0
  168. package/src/types/app.ts +65 -0
  169. package/src/types/index.ts +1064 -0
  170. package/src/types/returns.ts +135 -0
  171. package/src/types/schema.ts +22 -0
  172. package/src/types/type-utils.ts +86 -0
  173. package/src/types/units.ts +167 -0
@@ -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
+ }
@@ -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
+ }
@@ -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
+ }