@okay-e9g/hono-config 0.0.2 → 0.0.4
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/package.json
CHANGED
|
@@ -10,11 +10,17 @@ import { statusText } from '../schemas';
|
|
|
10
10
|
/**
|
|
11
11
|
* Creates the shared 404 handler used by the configured Hono factories.
|
|
12
12
|
*
|
|
13
|
+
* Falls back to a plain text 404 when no response helper has been installed.
|
|
14
|
+
*
|
|
13
15
|
* @internal
|
|
14
16
|
*/
|
|
15
17
|
export const notFound = <T extends Env>(): NotFoundHandler<T> => {
|
|
16
18
|
return (c) => {
|
|
17
|
-
const { response } = c.var as ResponseEnv['Variables']
|
|
19
|
+
const { response } = c.var as Partial<ResponseEnv['Variables']>;
|
|
20
|
+
|
|
21
|
+
if (response === undefined) {
|
|
22
|
+
return c.text(statusText[404], 404);
|
|
23
|
+
}
|
|
18
24
|
|
|
19
25
|
if (response.type === 'api') {
|
|
20
26
|
return c.json(response.error(404), 404);
|
package/src/handlers/on-error.ts
CHANGED
|
@@ -7,16 +7,32 @@ import type { Env, ErrorHandler } from 'hono/types';
|
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
|
|
9
9
|
import type { ResponseEnv } from '../middlewares/ensure-rt';
|
|
10
|
-
import { type ClientErrorStatusCode, type ServerErrorStatusCode,
|
|
10
|
+
import { type ClientErrorStatusCode, type ServerErrorStatusCode, statusText } from '../schemas';
|
|
11
|
+
|
|
12
|
+
interface TypedHTTPException extends Omit<HTTPException, 'status'> {
|
|
13
|
+
status: ClientErrorStatusCode & ServerErrorStatusCode;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const assertHTTPException = (err: Error): err is TypedHTTPException => {
|
|
17
|
+
return err instanceof HTTPException || (err instanceof Error && 'getResponse' in err && 'status' in err);
|
|
18
|
+
};
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
21
|
* Creates the shared error handler used by the configured Hono factories.
|
|
14
22
|
*
|
|
23
|
+
* Errors are rethrown when no response helper has been installed, allowing
|
|
24
|
+
* Hono's fallback error handling to handle apps that are not using this
|
|
25
|
+
* package's response envelopes.
|
|
26
|
+
*
|
|
15
27
|
* @internal
|
|
16
28
|
*/
|
|
17
29
|
export const onError = <T extends Env>(): ErrorHandler<T> => {
|
|
18
30
|
return (err, c) => {
|
|
19
|
-
const { response } = c.var as ResponseEnv['Variables']
|
|
31
|
+
const { response } = c.var as Partial<ResponseEnv['Variables']>;
|
|
32
|
+
|
|
33
|
+
if (response === undefined) {
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
20
36
|
|
|
21
37
|
if (err instanceof z.ZodError) {
|
|
22
38
|
if (response.type === 'api') {
|
|
@@ -26,14 +42,14 @@ export const onError = <T extends Env>(): ErrorHandler<T> => {
|
|
|
26
42
|
return c.json(response.error(z.flattenError(err)));
|
|
27
43
|
}
|
|
28
44
|
|
|
29
|
-
if (err
|
|
45
|
+
if (assertHTTPException(err)) {
|
|
30
46
|
const { message, status } = err;
|
|
31
47
|
|
|
32
48
|
if (response.type === 'api') {
|
|
33
|
-
return c.json(response.error(status
|
|
49
|
+
return c.json(response.error(status, message), status);
|
|
34
50
|
}
|
|
35
51
|
|
|
36
|
-
return c.json(response.error(message === '' ? statusText[status
|
|
52
|
+
return c.json(response.error(message === '' ? statusText[status] : message));
|
|
37
53
|
}
|
|
38
54
|
|
|
39
55
|
const errMessage = err instanceof Error ? err.message : err;
|
|
@@ -30,7 +30,7 @@ export type OpenAPIHonoFactory<T extends Env> = Omit<Factory<T>, 'createApp'> &
|
|
|
30
30
|
*
|
|
31
31
|
* The generated apps use non-strict routing, throw validation failures from the
|
|
32
32
|
* OpenAPI default hook, install the shared not-found and error handlers, enable
|
|
33
|
-
* SuperJSON response serialization, apply
|
|
33
|
+
* SuperJSON response serialization, apply application middleware when present,
|
|
34
34
|
* and finish with the response-type guard.
|
|
35
35
|
*
|
|
36
36
|
* Include exactly one response-type middleware, such as `apiResponseType()` or
|
|
@@ -61,9 +61,12 @@ export const createOpenAPIHonoFactory = <T extends Env>({
|
|
|
61
61
|
|
|
62
62
|
app.notFound(notFoundHandler());
|
|
63
63
|
app.onError(onErrorHandler());
|
|
64
|
-
|
|
65
64
|
app.use(superjson());
|
|
66
|
-
|
|
65
|
+
|
|
66
|
+
if (appMiddlewares.length) {
|
|
67
|
+
app.use(...appMiddlewares);
|
|
68
|
+
}
|
|
69
|
+
|
|
67
70
|
app.use(ensureResponseType());
|
|
68
71
|
|
|
69
72
|
return app;
|
package/src/helpers/factory.ts
CHANGED
|
@@ -36,8 +36,8 @@ export type CreateHonoFactoryOpts<T extends Env> = {
|
|
|
36
36
|
*
|
|
37
37
|
* The generated apps use non-strict routing, the shared not-found and error
|
|
38
38
|
* handlers, SuperJSON response serialization, any provided application
|
|
39
|
-
* middleware, and the response-type guard used by
|
|
40
|
-
* `rpcResponseType`.
|
|
39
|
+
* middleware when present, and the response-type guard used by
|
|
40
|
+
* `apiResponseType` and `rpcResponseType`.
|
|
41
41
|
*
|
|
42
42
|
* Include exactly one response-type middleware, such as `apiResponseType()` or
|
|
43
43
|
* `rpcResponseType()`, in `appMiddlewares` so the shared handlers can build the
|
|
@@ -59,9 +59,12 @@ export const createHonoFactory = <T extends Env>({
|
|
|
59
59
|
initApp: (app) => {
|
|
60
60
|
app.notFound(notFoundHandler());
|
|
61
61
|
app.onError(onErrorHandler());
|
|
62
|
-
|
|
63
62
|
app.use(superjson());
|
|
64
|
-
|
|
63
|
+
|
|
64
|
+
if (appMiddlewares.length) {
|
|
65
|
+
app.use(...appMiddlewares);
|
|
66
|
+
}
|
|
67
|
+
|
|
65
68
|
app.use(ensureResponseType());
|
|
66
69
|
},
|
|
67
70
|
});
|
|
@@ -33,12 +33,6 @@ type ErrorStatusCode = ClientErrorStatusCode | ServerErrorStatusCode;
|
|
|
33
33
|
|
|
34
34
|
type ResultStatusCode = Exclude<SuccessStatusCode, 204 | 205>;
|
|
35
35
|
|
|
36
|
-
const assertResponseTypeNotInitialized = (response: unknown): void => {
|
|
37
|
-
if (response !== undefined) {
|
|
38
|
-
throw new Error('Response type middleware already initialized.');
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
|
|
42
36
|
/**
|
|
43
37
|
* Hono environment contract added by `apiResponseType`.
|
|
44
38
|
*/
|
|
@@ -71,29 +65,31 @@ export interface ApiResponseEnv extends Env {
|
|
|
71
65
|
* Installs `c.var.response` helpers for conventional HTTP API responses.
|
|
72
66
|
*
|
|
73
67
|
* The helpers produce `{ success: false, error }` and `{ success: true, result }`
|
|
74
|
-
* envelopes validated by the exported API schemas.
|
|
68
|
+
* envelopes validated by the exported API schemas. If another response helper is
|
|
69
|
+
* already installed, the existing helper is kept so applications can compose
|
|
70
|
+
* middleware safely.
|
|
75
71
|
*
|
|
76
72
|
* @returns Hono middleware that adds the API response helper contract.
|
|
77
73
|
*/
|
|
78
74
|
export const apiResponseType = (): MiddlewareHandler<ApiResponseEnv> => {
|
|
79
75
|
return createMiddleware(async (c, next) => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
76
|
+
if (c.var.response === undefined) {
|
|
77
|
+
c.set('response', {
|
|
78
|
+
error: <T, U extends ErrorStatusCode>(status: U, error?: T) => {
|
|
79
|
+
return apiError.parse({
|
|
80
|
+
error: error === undefined || error === '' ? statusText[status] : error,
|
|
81
|
+
success: false,
|
|
82
|
+
}) as TypedApiError<T>;
|
|
83
|
+
},
|
|
84
|
+
result: <T, U extends ResultStatusCode>(status: U, result?: T) => {
|
|
85
|
+
return apiResult.parse({
|
|
86
|
+
result: result === undefined || result === '' ? statusText[status] : result,
|
|
87
|
+
success: true,
|
|
88
|
+
}) as TypedApiResult<T>;
|
|
89
|
+
},
|
|
90
|
+
type: 'api',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
97
93
|
|
|
98
94
|
await next();
|
|
99
95
|
});
|
|
@@ -136,23 +132,25 @@ export interface RpcResponseEnv extends Env {
|
|
|
136
132
|
* Installs `c.var.response` helpers for JSON-RPC 2.0 responses.
|
|
137
133
|
*
|
|
138
134
|
* The helpers produce `error` and `result` envelopes validated by the exported
|
|
139
|
-
* JSON-RPC schemas and default missing ids to the schema default.
|
|
135
|
+
* JSON-RPC schemas and default missing ids to the schema default. If another
|
|
136
|
+
* response helper is already installed, the existing helper is kept so
|
|
137
|
+
* applications can compose middleware safely.
|
|
140
138
|
*
|
|
141
139
|
* @returns Hono middleware that adds the RPC response helper contract.
|
|
142
140
|
*/
|
|
143
141
|
export const rpcResponseType = (): MiddlewareHandler<RpcResponseEnv> => {
|
|
144
142
|
return createMiddleware(async (c, next) => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
143
|
+
if (c.var.response === undefined) {
|
|
144
|
+
c.set('response', {
|
|
145
|
+
error: <T>(error?: T, id?: JsonRpc['id']) => {
|
|
146
|
+
return rpcError.parse({ error, id }) as TypedRpcError<T>;
|
|
147
|
+
},
|
|
148
|
+
result: <T>(result?: T, id?: JsonRpc['id']) => {
|
|
149
|
+
return rpcResult.parse({ id, result }) as TypedRpcResult<T>;
|
|
150
|
+
},
|
|
151
|
+
type: 'rpc',
|
|
152
|
+
});
|
|
153
|
+
}
|
|
156
154
|
|
|
157
155
|
await next();
|
|
158
156
|
});
|