@mpen/routekit 0.1.0 → 0.1.2

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 (133) hide show
  1. package/dist/bin.d.mts +4 -0
  2. package/dist/client/react.d.mts +178 -0
  3. package/dist/client/react.mjs +142 -0
  4. package/dist/client.d.mts +433 -0
  5. package/dist/client.mjs +264 -0
  6. package/dist/content-BuDOmhH_.mjs +102 -0
  7. package/dist/core-CzUCxvGk.d.mts +140 -0
  8. package/dist/core-DbmQauwS.mjs +81 -0
  9. package/dist/handlers.d.mts +72 -0
  10. package/dist/handlers.mjs +153 -0
  11. package/dist/index.d.mts +3 -0
  12. package/dist/index.mjs +1152 -0
  13. package/dist/middleware.d.mts +388 -0
  14. package/dist/middleware.mjs +1222 -0
  15. package/dist/request-Dn0zc-xm.mjs +1025 -0
  16. package/dist/response/content.d.mts +79 -0
  17. package/dist/response/content.mjs +2 -0
  18. package/dist/response/json-rpc.d.mts +1 -0
  19. package/dist/response/json-rpc.mjs +1 -0
  20. package/dist/response/problem/valibot.d.mts +230 -0
  21. package/dist/response/problem/valibot.mjs +258 -0
  22. package/dist/response/problem.d.mts +415 -0
  23. package/dist/response/problem.mjs +183 -0
  24. package/dist/response/status.d.mts +45 -0
  25. package/dist/response/status.mjs +2 -0
  26. package/dist/responses-B379Ep9Y.d.mts +296 -0
  27. package/dist/responses-BpVrgeYi.mjs +101 -0
  28. package/dist/router-Cwb7ak0J.d.mts +1819 -0
  29. package/dist/routes.d.mts +282 -0
  30. package/dist/routes.mjs +311 -0
  31. package/dist/status-C-8mw-FB.mjs +59 -0
  32. package/dist/valibot-D7liFYyB.d.mts +290 -0
  33. package/dist/valibot-Du97X-TS.mjs +326 -0
  34. package/package.json +8 -2
  35. package/src/bin/gen-api-client.test.ts +0 -70
  36. package/src/bin/gen-api-client.ts +0 -986
  37. package/src/client/headers.ts +0 -31
  38. package/src/client/index.ts +0 -8
  39. package/src/client/promise.ts +0 -11
  40. package/src/client/react/index.test.tsx +0 -266
  41. package/src/client/react/index.ts +0 -431
  42. package/src/client/responses.test.ts +0 -151
  43. package/src/client/responses.ts +0 -278
  44. package/src/client/transport.ts +0 -74
  45. package/src/client/transports/body-codec.ts +0 -61
  46. package/src/client/transports/fetch.ts +0 -113
  47. package/src/client/tsconfig.json +0 -9
  48. package/src/client/types.ts +0 -15
  49. package/src/client/url.ts +0 -31
  50. package/src/index.ts +0 -63
  51. package/src/router/fetch-types.ts +0 -13
  52. package/src/router/handlers/index.ts +0 -2
  53. package/src/router/handlers/openapi/index.ts +0 -2
  54. package/src/router/handlers/openapi/openapi.ts +0 -293
  55. package/src/router/integration/zod-openapi.test.ts +0 -74
  56. package/src/router/lib/charset.test.ts +0 -22
  57. package/src/router/lib/charset.ts +0 -133
  58. package/src/router/lib/collections.ts +0 -3
  59. package/src/router/lib/format.test.ts +0 -67
  60. package/src/router/lib/format.ts +0 -35
  61. package/src/router/lib/host.ts +0 -4
  62. package/src/router/lib/json-schema.ts +0 -6
  63. package/src/router/lib/media-type.test.ts +0 -122
  64. package/src/router/lib/media-type.ts +0 -289
  65. package/src/router/lib/pathname.test.ts +0 -18
  66. package/src/router/lib/pathname.ts +0 -19
  67. package/src/router/lib/route-names.ts +0 -70
  68. package/src/router/lib/route-normalize.test.ts +0 -36
  69. package/src/router/lib/route-normalize.ts +0 -67
  70. package/src/router/lib/schema-merge.ts +0 -56
  71. package/src/router/middleware/accept-ctx.test.ts +0 -33
  72. package/src/router/middleware/accept-ctx.ts +0 -12
  73. package/src/router/middleware/body-limit.test.ts +0 -112
  74. package/src/router/middleware/body-limit.ts +0 -121
  75. package/src/router/middleware/content-type-context.ts +0 -0
  76. package/src/router/middleware/cors.test.ts +0 -269
  77. package/src/router/middleware/cors.ts +0 -490
  78. package/src/router/middleware/csrf.test.ts +0 -106
  79. package/src/router/middleware/csrf.ts +0 -192
  80. package/src/router/middleware/define.ts +0 -249
  81. package/src/router/middleware/index.ts +0 -34
  82. package/src/router/middleware/jsxhtml-response.ts +0 -0
  83. package/src/router/middleware/oas-swagger.ts +0 -0
  84. package/src/router/middleware/rate-limit.test.ts +0 -886
  85. package/src/router/middleware/rate-limit.ts +0 -920
  86. package/src/router/middleware/request-id-ctx.test.ts +0 -183
  87. package/src/router/middleware/request-id-ctx.ts +0 -135
  88. package/src/router/middleware/request-logger-format.test.ts +0 -16
  89. package/src/router/middleware/request-logger-format.ts +0 -269
  90. package/src/router/middleware/request-logger.test.ts +0 -267
  91. package/src/router/middleware/request-logger.ts +0 -131
  92. package/src/router/middleware/start-time-ctx.ts +0 -5
  93. package/src/router/request.ts +0 -611
  94. package/src/router/response/core.ts +0 -181
  95. package/src/router/response/directives.ts +0 -233
  96. package/src/router/response/formats/content/bodyless.ts +0 -54
  97. package/src/router/response/formats/content/content.ts +0 -79
  98. package/src/router/response/formats/content/index.ts +0 -2
  99. package/src/router/response/formats/json-rpc/index.ts +0 -2
  100. package/src/router/response/formats/problem/badRequest.ts +0 -90
  101. package/src/router/response/formats/problem/conflict.ts +0 -90
  102. package/src/router/response/formats/problem/created.ts +0 -40
  103. package/src/router/response/formats/problem/index.ts +0 -27
  104. package/src/router/response/formats/problem/notFound.ts +0 -90
  105. package/src/router/response/formats/problem/permissionDenied.ts +0 -90
  106. package/src/router/response/formats/problem/problem.test.ts +0 -888
  107. package/src/router/response/formats/problem/rateLimited.ts +0 -90
  108. package/src/router/response/formats/problem/responses.ts +0 -219
  109. package/src/router/response/formats/problem/root-errors.ts +0 -48
  110. package/src/router/response/formats/problem/sessionExpired.ts +0 -90
  111. package/src/router/response/formats/problem/types.ts +0 -170
  112. package/src/router/response/formats/problem/unauthenticated.ts +0 -90
  113. package/src/router/response/formats/problem/valibot.ts +0 -410
  114. package/src/router/response/formats/status/index.ts +0 -1
  115. package/src/router/response/formats/status/responses.ts +0 -59
  116. package/src/router/response/formats/status/status.test.ts +0 -21
  117. package/src/router/response/framers.ts +0 -85
  118. package/src/router/response/index.ts +0 -28
  119. package/src/router/response/openapi.test.ts +0 -96
  120. package/src/router/response/openapi.ts +0 -1
  121. package/src/router/response/serializers.ts +0 -66
  122. package/src/router/response/stream.ts +0 -35
  123. package/src/router/router.test.ts +0 -1571
  124. package/src/router/router.ts +0 -1965
  125. package/src/router/routes/index.ts +0 -46
  126. package/src/router/routes/valibot/index.ts +0 -18
  127. package/src/router/routes/valibot/valibot.ts +0 -1393
  128. package/src/router/routes/valibot.test.ts +0 -286
  129. package/src/router/routes/zod/index.ts +0 -18
  130. package/src/router/routes/zod/zod.ts +0 -1318
  131. package/src/router/routes/zod.test.ts +0 -280
  132. package/src/router/server-interface.ts +0 -31
  133. package/src/router/types.ts +0 -657
@@ -1,90 +0,0 @@
1
- import { HttpStatus } from '@mpen/http'
2
- import type { RoutekitResponse } from '../../core'
3
- import { problem, type ProblemResponseInit } from './responses'
4
- import type { ProblemResponse } from './types'
5
-
6
- /**
7
- * Options accepted by [`rateLimited`]{@link rateLimited}.
8
- *
9
- * @example
10
- * ```ts
11
- * rateLimited({
12
- * message: 'Too many requests. Please try again later.',
13
- * })
14
- * ```
15
- *
16
- * @typeParam Code - Machine-readable primary error code.
17
- */
18
- export interface RateLimitedInit<Code extends string = 'rate_limited'> extends Omit<
19
- ProblemResponseInit<Code>,
20
- 'code' | 'status' | 'message'
21
- > {
22
- /**
23
- * Machine-readable error code. Defaults to `'rate_limited'`.
24
- */
25
- code?: Code
26
-
27
- /**
28
- * Human-readable problem message.
29
- */
30
- message?: string
31
-
32
- /**
33
- * HTTP status code for this response. Defaults to `429`.
34
- */
35
- status?: number | HttpStatus
36
- }
37
-
38
- /**
39
- * Create a standard 429 Too Many Requests problem response envelope.
40
- *
41
- * @example
42
- * ```ts
43
- * return rateLimited('Rate limit exceeded. Please wait 60 seconds.')
44
- * ```
45
- *
46
- * @param message - Human-readable problem message.
47
- * @param init - Optional extra problem response options.
48
- * @returns Routekit logical response with a `'rate_limited'` [`ProblemResponse`]{@link ProblemResponse}.
49
- */
50
- export function rateLimited(
51
- message: string,
52
- init?: Omit<RateLimitedInit<'rate_limited'>, 'message'>,
53
- ): RoutekitResponse<ProblemResponse<'rate_limited'>>
54
-
55
- /**
56
- * Create a standard 429 Too Many Requests problem response envelope.
57
- *
58
- * @example
59
- * ```ts
60
- * return rateLimited({ message: 'Rate limit exceeded.' })
61
- * ```
62
- *
63
- * @param init - Optional problem response options.
64
- * @returns Routekit logical response with a [`ProblemResponse`]{@link ProblemResponse}.
65
- * @typeParam Code - Machine-readable primary error code.
66
- */
67
- export function rateLimited<const Code extends string = 'rate_limited'>(
68
- init?: RateLimitedInit<Code>,
69
- ): RoutekitResponse<ProblemResponse<Code>>
70
-
71
- export function rateLimited<const Code extends string = 'rate_limited'>(
72
- messageOrInit?: string | RateLimitedInit<Code>,
73
- init?: Omit<RateLimitedInit<Code>, 'message'>,
74
- ): RoutekitResponse<ProblemResponse<Code>> {
75
- if (typeof messageOrInit === 'string') {
76
- return problem({
77
- ...init,
78
- code: (init?.code ?? 'rate_limited') as Code,
79
- message: messageOrInit,
80
- status: init?.status ?? HttpStatus.TOO_MANY_REQUESTS,
81
- })
82
- }
83
-
84
- return problem({
85
- ...messageOrInit,
86
- code: (messageOrInit?.code ?? 'rate_limited') as Code,
87
- message: messageOrInit?.message ?? 'Rate limited',
88
- status: messageOrInit?.status ?? HttpStatus.TOO_MANY_REQUESTS,
89
- })
90
- }
@@ -1,219 +0,0 @@
1
- import { HttpStatus } from '@mpen/http'
2
- import { response, type RoutekitResponse, type RoutekitResponseInit } from '../../core'
3
- import type { SuccessResponse, ProblemIssue, ProblemResponse } from './types'
4
-
5
- /**
6
- * Default primary error code for validation problem responses.
7
- *
8
- * @example
9
- * ```ts
10
- * validationProblem([{ code: 'required', message: 'Name is required' }])
11
- * ```
12
- */
13
- export const VALIDATION_PROBLEM_CODE = 'validation_failed'
14
-
15
- /**
16
- * Options accepted by [`ok`]{@link ok}.
17
- *
18
- * @example
19
- * ```ts
20
- * ok({ id: 'user_123' }, { meta: { requestId: 'req_123' } })
21
- * ```
22
- *
23
- * @typeParam Meta - Optional metadata payload type.
24
- */
25
- export interface SuccessResponseInit<Meta = unknown> extends Omit<RoutekitResponseInit, 'status'> {
26
- /**
27
- * Optional response metadata.
28
- */
29
- meta?: Meta
30
- }
31
-
32
- /**
33
- * Options accepted by [`problem`]{@link problem}.
34
- *
35
- * @example
36
- * ```ts
37
- * problem({
38
- * code: 'not_found',
39
- * status: 404,
40
- * message: 'No user exists for the provided id.',
41
- * title: 'User not found',
42
- * })
43
- * ```
44
- *
45
- * @typeParam Code - Machine-readable primary error code.
46
- * @typeParam Issue - Issue shape used for validation or business-rule details.
47
- */
48
- export interface ProblemResponseInit<
49
- Code extends string = string,
50
- Issue extends ProblemIssue = ProblemIssue,
51
- Status extends number = number,
52
- > extends Omit<RoutekitResponseInit, 'status'> {
53
- /**
54
- * Machine-readable error code.
55
- */
56
- code: Code
57
-
58
- /**
59
- * Human-readable problem message clients can display by default.
60
- */
61
- message: string
62
-
63
- /**
64
- * HTTP status code for this response.
65
- */
66
- status: Status
67
-
68
- /**
69
- * Optional short problem heading.
70
- */
71
- title?: string
72
-
73
- /**
74
- * Optional validation or business-rule issues.
75
- */
76
- issues?: readonly Issue[]
77
- }
78
-
79
- /**
80
- * Options accepted by [`validationProblem`]{@link validationProblem}.
81
- *
82
- * @example
83
- * ```ts
84
- * validationProblem([{ code: 'invalid_type', message: 'Expected a string' }], {
85
- * message: 'The request body was invalid.',
86
- * })
87
- * ```
88
- *
89
- * @typeParam Code - Machine-readable primary error code.
90
- * @typeParam Issue - Issue shape used for validation details.
91
- */
92
- export interface ValidationProblemInit<
93
- Code extends string = typeof VALIDATION_PROBLEM_CODE,
94
- Issue extends ProblemIssue = ProblemIssue,
95
- Status extends number = number,
96
- > extends Omit<ProblemResponseInit<Code, Issue, Status>, 'code' | 'message' | 'status' | 'issues'> {
97
- /**
98
- * Machine-readable validation error code.
99
- */
100
- code?: Code
101
-
102
- /**
103
- * Human-readable validation summary.
104
- */
105
- message?: string
106
-
107
- /**
108
- * HTTP status code for this response. Defaults to `400`.
109
- */
110
- status?: Status
111
- }
112
-
113
- function withDefinedOptional<Value extends object, Key extends string, Field>(
114
- value: Value,
115
- key: Key,
116
- field: Field | undefined,
117
- ): Value | (Value & Record<Key, Field>) {
118
- if (field === undefined) return value
119
- return { ...value, [key]: field } as Value & Record<Key, Field>
120
- }
121
-
122
- /**
123
- * Create a `200 OK` standard response envelope.
124
- *
125
- * @example
126
- * ```ts
127
- * router.get('/users/:id', () => ok({ id: 'user_123' }))
128
- * ```
129
- *
130
- * @param data - Successful response payload.
131
- * @param init - Response headers and optional metadata.
132
- * @returns Routekit logical response with an [`SuccessResponse`]{@link SuccessResponse} body.
133
- * @typeParam Data - Successful response payload type.
134
- * @typeParam Meta - Optional metadata payload type.
135
- */
136
- export function ok<const Data, const Meta = unknown>(
137
- data: Data,
138
- init: SuccessResponseInit<Meta> = {},
139
- ): RoutekitResponse<SuccessResponse<Data, Meta>, HttpStatus.OK> {
140
- const { meta, ...responseInit } = init
141
- const body = withDefinedOptional(
142
- { success: true, data } as const,
143
- 'meta',
144
- meta,
145
- ) as SuccessResponse<Data, Meta>
146
- return response(body, { ...responseInit, status: HttpStatus.OK })
147
- }
148
-
149
- /**
150
- * Create a standard problem response envelope.
151
- *
152
- * @example
153
- * ```ts
154
- * return problem({
155
- * code: 'not_found',
156
- * status: 404,
157
- * message: 'No user exists for the provided id.',
158
- * title: 'User not found',
159
- * })
160
- * ```
161
- *
162
- * @param init - Problem response data, headers, and status.
163
- * @returns Routekit logical response with a [`ProblemResponse`]{@link ProblemResponse} body.
164
- * @typeParam Code - Machine-readable primary error code.
165
- * @typeParam Issue - Issue shape used for validation or business-rule details.
166
- */
167
- export function problem<
168
- const Code extends string,
169
- const Issue extends ProblemIssue = ProblemIssue,
170
- const Status extends number = number,
171
- >(
172
- init: ProblemResponseInit<Code, Issue, Status>,
173
- ): RoutekitResponse<ProblemResponse<Code, Issue>, Status> {
174
- const { code, message, status, title, issues, ...responseInit } = init
175
- const error = withDefinedOptional(
176
- {
177
- code,
178
- message,
179
- },
180
- 'title',
181
- title,
182
- )
183
- const body = withDefinedOptional({ success: false, error } as const, 'issues', issues)
184
-
185
- return response(body as ProblemResponse<Code, Issue>, { ...responseInit, status })
186
- }
187
-
188
- /**
189
- * Create a standard validation problem response envelope.
190
- *
191
- * @example
192
- * ```ts
193
- * return validationProblem([
194
- * { code: 'required', message: 'Email is required', path: ['body', 'email'] },
195
- * ])
196
- * ```
197
- *
198
- * @param issues - Validation issues to include in the response.
199
- * @param init - Optional problem response overrides and headers.
200
- * @returns Routekit logical response with a validation [`ProblemResponse`]{@link ProblemResponse}.
201
- * @typeParam Issue - Issue shape used for validation details.
202
- * @typeParam Code - Machine-readable primary error code.
203
- */
204
- export function validationProblem<
205
- const Issue extends ProblemIssue,
206
- const Code extends string = typeof VALIDATION_PROBLEM_CODE,
207
- const Status extends number = HttpStatus.BAD_REQUEST,
208
- >(
209
- issues: readonly Issue[],
210
- init: ValidationProblemInit<Code, Issue, Status> = {},
211
- ): RoutekitResponse<ProblemResponse<Code, Issue>, Status | HttpStatus.BAD_REQUEST> {
212
- return problem({
213
- ...init,
214
- code: init.code ?? (VALIDATION_PROBLEM_CODE as Code),
215
- message: init.message ?? 'Validation failed',
216
- status: init.status ?? HttpStatus.BAD_REQUEST,
217
- issues,
218
- })
219
- }
@@ -1,48 +0,0 @@
1
- import { HttpStatus } from '@mpen/http'
2
- import type { AnyContext, RouterExtension } from '../../../types'
3
- import { problem } from './responses'
4
-
5
- /**
6
- * Install standard problem-envelope handlers for router-level errors.
7
- *
8
- * @example
9
- * ```ts
10
- * const router = new Router().install(problemRootErrors())
11
- * ```
12
- *
13
- * @returns Router extension that registers not-found, method, media-type, and internal-error handlers.
14
- * @typeParam Ctx - Context carried by the router being configured.
15
- */
16
- export function problemRootErrors<Ctx extends object = AnyContext>(): RouterExtension<Ctx> {
17
- return (router) => {
18
- router
19
- .onNotFound(() =>
20
- problem({
21
- code: 'not_found',
22
- message: 'Not found',
23
- status: HttpStatus.NOT_FOUND,
24
- }),
25
- )
26
- .onMethodNotAllowed(() =>
27
- problem({
28
- code: 'method_not_allowed',
29
- message: 'Method not allowed',
30
- status: HttpStatus.METHOD_NOT_ALLOWED,
31
- }),
32
- )
33
- .onUnsupportedMediaType(() =>
34
- problem({
35
- code: 'unsupported_media_type',
36
- message: 'Unsupported media type',
37
- status: HttpStatus.UNSUPPORTED_MEDIA_TYPE,
38
- }),
39
- )
40
- .onInternalError(() =>
41
- problem({
42
- code: 'internal_server_error',
43
- message: 'Internal server error',
44
- status: HttpStatus.INTERNAL_SERVER_ERROR,
45
- }),
46
- )
47
- }
48
- }
@@ -1,90 +0,0 @@
1
- import { HttpStatus } from '@mpen/http'
2
- import type { RoutekitResponse } from '../../core'
3
- import { problem, type ProblemResponseInit } from './responses'
4
- import type { ProblemResponse } from './types'
5
-
6
- /**
7
- * Options accepted by [`sessionExpired`]{@link sessionExpired}.
8
- *
9
- * @example
10
- * ```ts
11
- * sessionExpired({
12
- * message: 'Your login session has expired. Please log in again.',
13
- * })
14
- * ```
15
- *
16
- * @typeParam Code - Machine-readable primary error code.
17
- */
18
- export interface SessionExpiredInit<Code extends string = 'session_expired'> extends Omit<
19
- ProblemResponseInit<Code>,
20
- 'code' | 'status' | 'message'
21
- > {
22
- /**
23
- * Machine-readable error code. Defaults to `'session_expired'`.
24
- */
25
- code?: Code
26
-
27
- /**
28
- * Human-readable problem message.
29
- */
30
- message?: string
31
-
32
- /**
33
- * HTTP status code for this response. Defaults to `401`.
34
- */
35
- status?: number | HttpStatus
36
- }
37
-
38
- /**
39
- * Create a standard 401 Session Expired problem response envelope.
40
- *
41
- * @example
42
- * ```ts
43
- * return sessionExpired('Session has timed out.')
44
- * ```
45
- *
46
- * @param message - Human-readable problem message.
47
- * @param init - Optional extra problem response options.
48
- * @returns Routekit logical response with a `'session_expired'` [`ProblemResponse`]{@link ProblemResponse}.
49
- */
50
- export function sessionExpired(
51
- message: string,
52
- init?: Omit<SessionExpiredInit<'session_expired'>, 'message'>,
53
- ): RoutekitResponse<ProblemResponse<'session_expired'>>
54
-
55
- /**
56
- * Create a standard 401 Session Expired problem response envelope.
57
- *
58
- * @example
59
- * ```ts
60
- * return sessionExpired({ message: 'Session expired.' })
61
- * ```
62
- *
63
- * @param init - Optional problem response options.
64
- * @returns Routekit logical response with a [`ProblemResponse`]{@link ProblemResponse}.
65
- * @typeParam Code - Machine-readable primary error code.
66
- */
67
- export function sessionExpired<const Code extends string = 'session_expired'>(
68
- init?: SessionExpiredInit<Code>,
69
- ): RoutekitResponse<ProblemResponse<Code>>
70
-
71
- export function sessionExpired<const Code extends string = 'session_expired'>(
72
- messageOrInit?: string | SessionExpiredInit<Code>,
73
- init?: Omit<SessionExpiredInit<Code>, 'message'>,
74
- ): RoutekitResponse<ProblemResponse<Code>> {
75
- if (typeof messageOrInit === 'string') {
76
- return problem({
77
- ...init,
78
- code: (init?.code ?? 'session_expired') as Code,
79
- message: messageOrInit,
80
- status: init?.status ?? HttpStatus.UNAUTHORIZED,
81
- })
82
- }
83
-
84
- return problem({
85
- ...messageOrInit,
86
- code: (messageOrInit?.code ?? 'session_expired') as Code,
87
- message: messageOrInit?.message ?? 'Session expired',
88
- status: messageOrInit?.status ?? HttpStatus.UNAUTHORIZED,
89
- })
90
- }
@@ -1,170 +0,0 @@
1
- /**
2
- * Path segment used to locate a validation or business-rule issue.
3
- *
4
- * @example
5
- * ```ts
6
- * const path: ProblemIssuePathSegment[] = ['body', 'users', 0, 'email']
7
- * ```
8
- */
9
- export type ProblemIssuePathSegment = string | number
10
-
11
- /**
12
- * A single issue associated with a problem response.
13
- *
14
- * @example
15
- * ```ts
16
- * const issue: ProblemIssue<'required'> = {
17
- * code: 'required',
18
- * message: 'Email is required',
19
- * path: ['body', 'email'],
20
- * }
21
- * ```
22
- *
23
- * @typeParam Code - Machine-readable issue code.
24
- */
25
- export interface ProblemIssue<Code extends string = string> {
26
- /**
27
- * Machine-readable issue code.
28
- */
29
- code: Code
30
-
31
- /**
32
- * Human-readable issue message.
33
- */
34
- message: string
35
-
36
- /**
37
- * Structured path to the invalid value.
38
- */
39
- path?: readonly ProblemIssuePathSegment[]
40
-
41
- /**
42
- * Expected value description.
43
- */
44
- expected?: string
45
-
46
- /**
47
- * Received value description.
48
- */
49
- received?: string
50
- }
51
-
52
- /**
53
- * Primary problem metadata that clients can switch on.
54
- *
55
- * @example
56
- * ```ts
57
- * const error: ProblemError<'not_found'> = {
58
- * code: 'not_found',
59
- * message: 'No user exists for the provided id.',
60
- * title: 'User not found',
61
- * }
62
- * ```
63
- *
64
- * @typeParam Code - Machine-readable error code.
65
- */
66
- export interface ProblemError<Code extends string = string> {
67
- /**
68
- * Machine-readable error code.
69
- */
70
- code: Code
71
-
72
- /**
73
- * Human-readable problem message clients can display by default.
74
- */
75
- message: string
76
-
77
- /**
78
- * Optional short problem heading.
79
- */
80
- title?: string
81
- }
82
-
83
- /**
84
- * Successful standard response envelope.
85
- *
86
- * @example
87
- * ```ts
88
- * const response: SuccessResponse<{ id: string }> = {
89
- * success: true,
90
- * data: { id: 'user_123' },
91
- * }
92
- * ```
93
- *
94
- * @typeParam Data - Successful response payload type.
95
- * @typeParam Meta - Optional metadata payload type.
96
- */
97
- export interface SuccessResponse<Data = unknown, Meta = unknown> {
98
- /**
99
- * Discriminator for successful responses.
100
- */
101
- success: true
102
-
103
- /**
104
- * Successful response payload.
105
- */
106
- data: Data
107
-
108
- /**
109
- * Optional response metadata.
110
- */
111
- meta?: Meta
112
- }
113
-
114
- /**
115
- * Error standard response envelope.
116
- *
117
- * @example
118
- * ```ts
119
- * const response: ProblemResponse<'validation_failed'> = {
120
- * success: false,
121
- * error: {
122
- * code: 'validation_failed',
123
- * message: 'Validation failed',
124
- * },
125
- * issues: [{ code: 'required', message: 'Email is required', path: ['body', 'email'] }],
126
- * }
127
- * ```
128
- *
129
- * @typeParam Code - Machine-readable primary error code.
130
- * @typeParam Issue - Issue shape used for validation or business-rule details.
131
- */
132
- export interface ProblemResponse<
133
- Code extends string = string,
134
- Issue extends ProblemIssue = ProblemIssue,
135
- > {
136
- /**
137
- * Discriminator for problem responses.
138
- */
139
- success: false
140
-
141
- /**
142
- * Primary error clients can switch on.
143
- */
144
- error: ProblemError<Code>
145
-
146
- /**
147
- * Optional validation or business-rule issues.
148
- */
149
- issues?: readonly Issue[]
150
- }
151
-
152
- /**
153
- * Standard response union for successful and problem responses.
154
- *
155
- * @example
156
- * ```ts
157
- * type GetUserResponse = StandardResponse<{ id: string }, 'not_found'>
158
- * ```
159
- *
160
- * @typeParam Data - Successful response payload type.
161
- * @typeParam Code - Machine-readable primary error code.
162
- * @typeParam Issue - Issue shape used for validation or business-rule details.
163
- * @typeParam Meta - Optional metadata payload type.
164
- */
165
- export type StandardResponse<
166
- Data = unknown,
167
- Code extends string = string,
168
- Issue extends ProblemIssue = ProblemIssue,
169
- Meta = unknown,
170
- > = SuccessResponse<Data, Meta> | ProblemResponse<Code, Issue>
@@ -1,90 +0,0 @@
1
- import { HttpStatus } from '@mpen/http'
2
- import type { RoutekitResponse } from '../../core'
3
- import { problem, type ProblemResponseInit } from './responses'
4
- import type { ProblemResponse } from './types'
5
-
6
- /**
7
- * Options accepted by [`unauthenticated`]{@link unauthenticated}.
8
- *
9
- * @example
10
- * ```ts
11
- * unauthenticated({
12
- * message: 'You must be logged in to access this resource.',
13
- * })
14
- * ```
15
- *
16
- * @typeParam Code - Machine-readable primary error code.
17
- */
18
- export interface UnauthenticatedInit<Code extends string = 'unauthenticated'> extends Omit<
19
- ProblemResponseInit<Code>,
20
- 'code' | 'status' | 'message'
21
- > {
22
- /**
23
- * Machine-readable error code. Defaults to `'unauthenticated'`.
24
- */
25
- code?: Code
26
-
27
- /**
28
- * Human-readable problem message.
29
- */
30
- message?: string
31
-
32
- /**
33
- * HTTP status code for this response. Defaults to `401`.
34
- */
35
- status?: number | HttpStatus
36
- }
37
-
38
- /**
39
- * Create a standard 401 Unauthenticated problem response envelope.
40
- *
41
- * @example
42
- * ```ts
43
- * return unauthenticated('Missing authorization token.')
44
- * ```
45
- *
46
- * @param message - Human-readable problem message.
47
- * @param init - Optional extra problem response options.
48
- * @returns Routekit logical response with a `'unauthenticated'` [`ProblemResponse`]{@link ProblemResponse}.
49
- */
50
- export function unauthenticated(
51
- message: string,
52
- init?: Omit<UnauthenticatedInit<'unauthenticated'>, 'message'>,
53
- ): RoutekitResponse<ProblemResponse<'unauthenticated'>>
54
-
55
- /**
56
- * Create a standard 401 Unauthenticated problem response envelope.
57
- *
58
- * @example
59
- * ```ts
60
- * return unauthenticated({ message: 'Invalid credentials.' })
61
- * ```
62
- *
63
- * @param init - Optional problem response options.
64
- * @returns Routekit logical response with a [`ProblemResponse`]{@link ProblemResponse}.
65
- * @typeParam Code - Machine-readable primary error code.
66
- */
67
- export function unauthenticated<const Code extends string = 'unauthenticated'>(
68
- init?: UnauthenticatedInit<Code>,
69
- ): RoutekitResponse<ProblemResponse<Code>>
70
-
71
- export function unauthenticated<const Code extends string = 'unauthenticated'>(
72
- messageOrInit?: string | UnauthenticatedInit<Code>,
73
- init?: Omit<UnauthenticatedInit<Code>, 'message'>,
74
- ): RoutekitResponse<ProblemResponse<Code>> {
75
- if (typeof messageOrInit === 'string') {
76
- return problem({
77
- ...init,
78
- code: (init?.code ?? 'unauthenticated') as Code,
79
- message: messageOrInit,
80
- status: init?.status ?? HttpStatus.UNAUTHORIZED,
81
- })
82
- }
83
-
84
- return problem({
85
- ...messageOrInit,
86
- code: (messageOrInit?.code ?? 'unauthenticated') as Code,
87
- message: messageOrInit?.message ?? 'Unauthenticated',
88
- status: messageOrInit?.status ?? HttpStatus.UNAUTHORIZED,
89
- })
90
- }