@rdlabo/workers-hono-kit 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +126 -11
  2. package/dist/ai/gateway.d.ts +54 -16
  3. package/dist/ai/gateway.js +37 -12
  4. package/dist/aws/cloudfront.d.ts +23 -5
  5. package/dist/aws/cloudfront.js +45 -6
  6. package/dist/aws/secrets-manager.d.ts +38 -4
  7. package/dist/aws/secrets-manager.js +48 -3
  8. package/dist/cache/kv-cache.d.ts +173 -10
  9. package/dist/cache/kv-cache.js +139 -7
  10. package/dist/db/connection.d.ts +56 -14
  11. package/dist/db/connection.js +39 -13
  12. package/dist/db/database.d.ts +159 -23
  13. package/dist/db/database.js +49 -5
  14. package/dist/db/index.d.ts +11 -0
  15. package/dist/db/index.js +11 -2
  16. package/dist/db/jst.d.ts +89 -6
  17. package/dist/db/jst.js +89 -23
  18. package/dist/db/orm-config.d.ts +61 -19
  19. package/dist/db/orm-config.js +43 -14
  20. package/dist/db/retry.d.ts +25 -3
  21. package/dist/db/retry.js +25 -3
  22. package/dist/db/write-result.d.ts +27 -4
  23. package/dist/db/write-result.js +22 -1
  24. package/dist/firebase/firebase-verifier.d.ts +53 -4
  25. package/dist/firebase/identity-toolkit.d.ts +54 -5
  26. package/dist/firebase/identity-toolkit.js +51 -0
  27. package/dist/firebase/jose-firebase-verifier.d.ts +79 -7
  28. package/dist/firebase/jose-firebase-verifier.js +68 -7
  29. package/dist/firebase/remote-verifier.d.ts +42 -4
  30. package/dist/firebase/remote-verifier.js +58 -9
  31. package/dist/http/app-env.d.ts +41 -8
  32. package/dist/http/app-env.js +38 -8
  33. package/dist/http/app-info.d.ts +25 -3
  34. package/dist/http/app-info.js +16 -2
  35. package/dist/http/http-status.d.ts +12 -3
  36. package/dist/http/http-status.js +12 -3
  37. package/dist/http/nest-error.d.ts +90 -29
  38. package/dist/http/nest-error.js +59 -18
  39. package/dist/http/user-protocol.d.ts +23 -3
  40. package/dist/http/user-protocol.js +14 -2
  41. package/dist/index.d.ts +11 -0
  42. package/dist/index.js +11 -3
  43. package/dist/middleware/auth.d.ts +74 -13
  44. package/dist/middleware/auth.js +30 -6
  45. package/dist/middleware/finalize-response.d.ts +30 -0
  46. package/dist/middleware/finalize-response.js +41 -12
  47. package/dist/middleware/validation.d.ts +83 -9
  48. package/dist/middleware/validation.js +52 -9
  49. package/dist/middleware/zod-coerce.d.ts +56 -2
  50. package/dist/middleware/zod-coerce.js +68 -9
  51. package/dist/stripe/client.d.ts +46 -9
  52. package/dist/stripe/client.js +41 -3
  53. package/dist/testing/auth.d.ts +58 -10
  54. package/dist/testing/auth.js +58 -10
  55. package/dist/testing/configurable-fake.d.ts +20 -9
  56. package/dist/testing/configurable-fake.js +23 -11
  57. package/dist/testing/db.d.ts +81 -12
  58. package/dist/testing/db.js +23 -1
  59. package/dist/testing/fakes.d.ts +77 -9
  60. package/dist/testing/fakes.js +69 -7
  61. package/dist/testing/index.d.ts +7 -0
  62. package/dist/testing/index.js +10 -5
  63. package/dist/testing/stripe-fixtures.d.ts +93 -3
  64. package/dist/testing/stripe-fixtures.js +93 -3
  65. package/package.json +1 -1
  66. package/src/ai/gateway.ts +66 -27
  67. package/src/aws/cloudfront.ts +46 -6
  68. package/src/aws/secrets-manager.ts +56 -7
  69. package/src/cache/kv-cache.ts +194 -12
  70. package/src/db/connection.ts +56 -14
  71. package/src/db/database.ts +160 -24
  72. package/src/db/index.ts +11 -2
  73. package/src/db/jst.ts +89 -23
  74. package/src/db/orm-config.ts +61 -19
  75. package/src/db/retry.ts +25 -3
  76. package/src/db/write-result.ts +27 -4
  77. package/src/firebase/firebase-verifier.ts +53 -4
  78. package/src/firebase/identity-toolkit.ts +57 -5
  79. package/src/firebase/jose-firebase-verifier.ts +79 -9
  80. package/src/firebase/remote-verifier.ts +58 -9
  81. package/src/http/app-env.ts +41 -8
  82. package/src/http/app-info.ts +25 -3
  83. package/src/http/http-status.ts +12 -3
  84. package/src/http/nest-error.ts +106 -37
  85. package/src/http/user-protocol.ts +23 -3
  86. package/src/index.ts +11 -3
  87. package/src/middleware/auth.ts +77 -15
  88. package/src/middleware/finalize-response.ts +41 -12
  89. package/src/middleware/validation.ts +89 -15
  90. package/src/middleware/zod-coerce.ts +68 -9
  91. package/src/stripe/client.ts +46 -9
  92. package/src/testing/auth.ts +58 -10
  93. package/src/testing/configurable-fake.ts +23 -11
  94. package/src/testing/db.ts +82 -13
  95. package/src/testing/fakes.ts +77 -9
  96. package/src/testing/index.ts +10 -5
  97. package/src/testing/stripe-fixtures.ts +93 -3
@@ -1,72 +1,133 @@
1
1
  import type { Context, Env } from 'hono';
2
2
  import type { ContentfulStatusCode } from 'hono/utils/http-status';
3
3
  /**
4
- * NestJS の既定例外フィルタが付ける reason phrase(フリート共通 = receptray/winecode/foodlabel
5
- * REASON_PHRASE / DEFAULT_MESSAGES と同一)。3 repo がそれぞれ手書きしていたものを一本化する。
4
+ * Reason phrases attached by the NestJS default exception filter, keyed by HTTP status code.
5
+ *
6
+ * @remarks
7
+ * Mirrors the `error` field values NestJS produces for common client-error statuses, so a Hono app can
8
+ * return byte-identical error bodies. Used as the default `reasonPhrases` map by {@link createNestErrorHandler}.
6
9
  */
7
10
  export declare const NEST_REASON_PHRASES: Record<number, string>;
8
- /** 想定外エラーの通報先に渡す文脈(request id 相関など)。フリート共通の最小形。 */
11
+ /**
12
+ * Contextual metadata passed to an {@link ErrorReporter} when reporting an unexpected error.
13
+ */
9
14
  export interface ErrorReportContext {
15
+ /** Correlation id for the failing request, if one is tracked. */
10
16
  requestId?: string;
11
17
  }
12
18
  /**
13
- * 想定外エラーの通報関数(Sentry 等)の型。各 repo container.reportError がこの形。
14
- * `createNestErrorHandler({ onUnhandledError })` に `(err, c) => reporter(err, { requestId: c.get('requestId') })`
15
- * の形で差し込む。Sentry 呼び出し自体は各 repo(@sentry/cloudflare は workers-hono-kit に持ち込まない)。
19
+ * Signature of a function that reports an unexpected (non-HTTP) error to an external sink such as Sentry.
20
+ *
21
+ * @remarks
22
+ * Wire it into {@link createNestErrorHandler} via `onUnhandledError`, e.g.
23
+ * `(err, c) => reporter(err, { requestId: c.get('requestId') })`. The reporting client itself is
24
+ * intentionally kept out of this kit; the consumer supplies the implementation.
25
+ *
26
+ * @param error - The thrown value being reported.
27
+ * @param context - Optional correlation context for the failing request.
16
28
  */
17
29
  export type ErrorReporter = (error: unknown, context?: ErrorReportContext) => void;
18
- /** http エラーとみなされた値から status / message / body を読むための最小形。 */
30
+ /**
31
+ * Minimal shape read from a value treated as an HTTP error: its status, message, and optional body.
32
+ *
33
+ * @internal
34
+ */
19
35
  interface HttpErrorLike {
36
+ /** HTTP status code to respond with. */
20
37
  status: ContentfulStatusCode;
38
+ /** Human-readable error message placed in the response body. */
21
39
  message: string;
22
- /** repo 固有 body の脱出口(winecode の HttpError.body 相当)。あればそのまま render する。 */
40
+ /**
41
+ * Escape hatch for a fully custom response body. When present, it is rendered verbatim instead of
42
+ * the NestJS-shaped body.
43
+ */
23
44
  body?: unknown;
24
45
  }
46
+ /**
47
+ * Options controlling how {@link createNestErrorHandler} shapes error responses.
48
+ *
49
+ * @typeParam E - The Hono environment type, so `onUnhandledError` receives a correctly typed context.
50
+ */
25
51
  export interface NestErrorHandlerOptions<E extends Env = Env> {
26
- /** reason phrase map。既定 `NEST_REASON_PHRASES`。 */
52
+ /** Status-to-reason-phrase map for the `error` field. Defaults to {@link NEST_REASON_PHRASES}. */
27
53
  reasonPhrases?: Record<number, string>;
28
54
  /**
29
- * `error` フィールドを省いて `{ statusCode, message }` のみ返す status。既定 `[401]`
30
- * NestJS generic `HttpException(msg, 401)` `error` を持たない)。
55
+ * Statuses that return only `{ statusCode, message }`, omitting the `error` field. Defaults to `[401]`,
56
+ * matching NestJS where a generic `HttpException(msg, 401)` carries no `error`.
31
57
  */
32
58
  bareStatuses?: readonly number[];
33
59
  /**
34
- * bare body のフィールド順序。既定 `'statusCode-first'`(= NestJS canonical / receptray・winecode)。
35
- * **foodlabel `'message-first'`** を指定して `{ message, error, statusCode }` byte-parity を保つ。
60
+ * Field order of the non-bare error body. Defaults to `'statusCode-first'` (the NestJS canonical order).
61
+ * Use `'message-first'` to emit `{ message, error, statusCode }` when byte parity requires it.
36
62
  */
37
63
  fieldOrder?: 'statusCode-first' | 'message-first';
38
64
  /**
39
- * reasonPhrases に無い(かつ bare でない)status `error` フォールバック。既定 `undefined`
40
- * (= reason 無しなら `error` を省く)。**winecode `'Error'`** を指定し、全 status `error` を必ず出す
41
- * (NestJS 既定例外フィルタの「error は常に存在」を忠実再現)。
65
+ * Fallback `error` value for statuses that are neither bare nor present in `reasonPhrases`. Defaults to
66
+ * `undefined`, meaning the `error` field is omitted when no reason phrase is known. Set to a string such
67
+ * as `'Error'` to always include an `error` field, faithfully reproducing the NestJS default exception
68
+ * filter behavior where `error` is always present.
42
69
  */
43
70
  fallbackReason?: string;
44
71
  /**
45
- * http エラー判定。既定は hono `HTTPException`。
46
- * **winecode は独自 `HttpError` を使う**ため `(e) => e instanceof HttpError` を渡す。
72
+ * Predicate identifying which thrown values are HTTP errors. Defaults to detecting Hono's `HTTPException`.
73
+ * Override it (e.g. `(e) => e instanceof MyHttpError`) when the app throws a custom HTTP error type.
47
74
  */
48
75
  isHttpError?: (err: unknown) => err is HttpErrorLike;
49
76
  /**
50
- * http エラーでない(= 想定外)エラーを 500 で返す前に呼ぶフック(Sentry 通報など)。
51
- * **receptray `container.reportError?.(err, { requestId })`** を差し込む。例外は握り潰す。
77
+ * Hook invoked before an unexpected (non-HTTP) error is returned as a 500, typically used to report the
78
+ * error (e.g. to Sentry). Any exception thrown by this hook is swallowed so reporting cannot alter the
79
+ * error response.
52
80
  */
53
81
  onUnhandledError?: (err: unknown, c: Context<E>) => void;
54
- /** 想定外エラー時の 500 body。既定 `{ statusCode: 500, message: 'Internal server error' }`。 */
82
+ /**
83
+ * Response body for unexpected errors returned as 500. Defaults to
84
+ * `{ statusCode: 500, message: 'Internal server error' }`.
85
+ */
55
86
  internalServerErrorBody?: unknown;
56
87
  }
57
88
  /**
58
- * NestJS の例外フィルタ相当の Hono `onError` ハンドラを作る(フリート共通)。
59
- * - http エラー(既定 `HTTPException`)→ Nest 形 body にマップ。`body` を持つ場合はそれを verbatim で返す。
60
- * - bareStatuses(既定 401)は `error` フィールド無し。
61
- * - それ以外(想定外エラー)→ `onUnhandledError` 通報 + `console.error` + 500。
89
+ * Create a Hono `onError` handler that maps thrown errors to NestJS-shaped error JSON.
90
+ *
91
+ * @remarks
92
+ * Reproduces the NestJS default exception filter so a Hono app returns byte-identical error bodies:
93
+ * - HTTP errors (by default `HTTPException`) are mapped to a NestJS-shaped body; if the error carries a
94
+ * custom `body`, that body is returned verbatim.
95
+ * - Statuses listed in `bareStatuses` (default `[401]`) omit the `error` field.
96
+ * - Any other (unexpected) error triggers `onUnhandledError`, is logged via `console.error`, and returns 500.
62
97
  *
63
- * `app.onError(createNestErrorHandler(...))` の形で使う。各 repo parity 差異(body 順序・
64
- * エラー型・通報フック)は options で吸収し、本体の分岐ロジックは共有する。
98
+ * Per-app differences in body field order, HTTP error type, and reporting hook are absorbed through
99
+ * {@link NestErrorHandlerOptions}, while the branching logic stays shared.
100
+ *
101
+ * @typeParam E - The Hono environment type propagated to `onUnhandledError`.
102
+ * @param options - Overrides for reason phrases, bare statuses, field order, error detection, and reporting.
103
+ * @returns A handler suitable for `app.onError(...)`.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * app.onError(
108
+ * createNestErrorHandler({
109
+ * fieldOrder: 'message-first',
110
+ * fallbackReason: 'Error',
111
+ * onUnhandledError: (err, c) => reportError(err, { requestId: c.get('requestId') }),
112
+ * }),
113
+ * );
114
+ * ```
65
115
  */
66
116
  export declare function createNestErrorHandler<E extends Env = Env>(options?: NestErrorHandlerOptions<E>): (err: Error, c: Context<E>) => Response;
67
117
  /**
68
- * Express/Nest 既定の未マッチルート 404 body を返す `notFound` ハンドラ。
69
- * `app.notFound(nestNotFoundHandler)` で使う(receptray/winecode は未実装の parity ギャップ)。
118
+ * Hono `notFound` handler that returns the canonical Express/NestJS unmatched-route 404 body.
119
+ *
120
+ * @remarks
121
+ * Produces `{ message: "Cannot <METHOD> <path>", error: 'Not Found', statusCode: 404 }`, matching the
122
+ * NestJS default 404 response so unmatched routes stay byte-identical.
123
+ *
124
+ * @param c - The Hono request context for the unmatched route.
125
+ * @returns A 404 JSON response.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * app.notFound(nestNotFoundHandler);
130
+ * ```
70
131
  */
71
132
  export declare function nestNotFoundHandler(c: Context): Response;
72
133
  export {};
@@ -1,6 +1,9 @@
1
1
  /**
2
- * NestJS の既定例外フィルタが付ける reason phrase(フリート共通 = receptray/winecode/foodlabel
3
- * REASON_PHRASE / DEFAULT_MESSAGES と同一)。3 repo がそれぞれ手書きしていたものを一本化する。
2
+ * Reason phrases attached by the NestJS default exception filter, keyed by HTTP status code.
3
+ *
4
+ * @remarks
5
+ * Mirrors the `error` field values NestJS produces for common client-error statuses, so a Hono app can
6
+ * return byte-identical error bodies. Used as the default `reasonPhrases` map by {@link createNestErrorHandler}.
4
7
  */
5
8
  export const NEST_REASON_PHRASES = {
6
9
  400: 'Bad Request',
@@ -9,33 +12,60 @@ export const NEST_REASON_PHRASES = {
9
12
  404: 'Not Found',
10
13
  };
11
14
  /**
12
- * hono `HTTPException` **構造的に**判定する(`instanceof` ではない)。workers-hono-kit は consumer に
13
- * symlink 同梱されるため、workers-hono-kit が解決する `hono` と consumer の `hono` が別インスタンスになり得る
14
- * (別コピーの HTTPException は `instanceof` で一致しない)。`getResponse()` と数値 `status` を持つかで
15
- * 判定すればモジュール境界をまたいでも、prod バンドルでも安定する。
15
+ * Structurally detect Hono's `HTTPException` without relying on `instanceof`.
16
+ *
17
+ * @remarks
18
+ * When this kit is symlinked into a consumer, the `hono` instance it resolves can differ from the
19
+ * consumer's `hono`, so an `HTTPException` from one copy fails an `instanceof` check against the other.
20
+ * Detecting the presence of a `getResponse()` method and a numeric `status` is stable across module
21
+ * boundaries and production bundles.
22
+ *
23
+ * @param err - The thrown value to test.
24
+ * @returns `true` when `err` looks like a Hono `HTTPException`.
25
+ *
26
+ * @internal
16
27
  */
17
28
  const isHTTPException = (err) => err instanceof Error &&
18
29
  typeof err.getResponse === 'function' &&
19
30
  typeof err.status === 'number';
20
31
  /**
21
- * NestJS の例外フィルタ相当の Hono `onError` ハンドラを作る(フリート共通)。
22
- * - http エラー(既定 `HTTPException`)→ Nest 形 body にマップ。`body` を持つ場合はそれを verbatim で返す。
23
- * - bareStatuses(既定 401)は `error` フィールド無し。
24
- * - それ以外(想定外エラー)→ `onUnhandledError` 通報 + `console.error` + 500。
32
+ * Create a Hono `onError` handler that maps thrown errors to NestJS-shaped error JSON.
33
+ *
34
+ * @remarks
35
+ * Reproduces the NestJS default exception filter so a Hono app returns byte-identical error bodies:
36
+ * - HTTP errors (by default `HTTPException`) are mapped to a NestJS-shaped body; if the error carries a
37
+ * custom `body`, that body is returned verbatim.
38
+ * - Statuses listed in `bareStatuses` (default `[401]`) omit the `error` field.
39
+ * - Any other (unexpected) error triggers `onUnhandledError`, is logged via `console.error`, and returns 500.
25
40
  *
26
- * `app.onError(createNestErrorHandler(...))` の形で使う。各 repo parity 差異(body 順序・
27
- * エラー型・通報フック)は options で吸収し、本体の分岐ロジックは共有する。
41
+ * Per-app differences in body field order, HTTP error type, and reporting hook are absorbed through
42
+ * {@link NestErrorHandlerOptions}, while the branching logic stays shared.
43
+ *
44
+ * @typeParam E - The Hono environment type propagated to `onUnhandledError`.
45
+ * @param options - Overrides for reason phrases, bare statuses, field order, error detection, and reporting.
46
+ * @returns A handler suitable for `app.onError(...)`.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * app.onError(
51
+ * createNestErrorHandler({
52
+ * fieldOrder: 'message-first',
53
+ * fallbackReason: 'Error',
54
+ * onUnhandledError: (err, c) => reportError(err, { requestId: c.get('requestId') }),
55
+ * }),
56
+ * );
57
+ * ```
28
58
  */
29
59
  export function createNestErrorHandler(options = {}) {
30
60
  const { reasonPhrases = NEST_REASON_PHRASES, bareStatuses = [401], fieldOrder = 'statusCode-first', isHttpError = isHTTPException, onUnhandledError, internalServerErrorBody = { statusCode: 500, message: 'Internal server error' }, fallbackReason, } = options;
31
61
  return (err, c) => {
32
62
  if (isHttpError(err)) {
33
- // repo 固有 body の脱出口(winecode)。
63
+ // Escape hatch for a custom error body: render it verbatim.
34
64
  if (err.body !== undefined) {
35
65
  return c.json(err.body, err.status);
36
66
  }
37
- // reasonPhrases[status] は型上 string だが noUncheckedIndexedAccess 無効のため実際は未定義になり得る。
38
- // 未登録 status fallbackReason フォールバックは意図的。
67
+ // reasonPhrases[status] is typed as string, but with noUncheckedIndexedAccess disabled it can be
68
+ // undefined at runtime. The fallbackReason fallback for unregistered statuses is intentional.
39
69
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
40
70
  const reason = bareStatuses.includes(err.status) ? undefined : (reasonPhrases[err.status] ?? fallbackReason);
41
71
  if (reason === undefined) {
@@ -50,15 +80,26 @@ export function createNestErrorHandler(options = {}) {
50
80
  onUnhandledError?.(err, c);
51
81
  }
52
82
  catch {
53
- // 通報はエラーレスポンスの挙動を変えてはならない。
83
+ // Reporting must never change the behavior of the error response.
54
84
  }
55
85
  console.error(err);
56
86
  return c.json(internalServerErrorBody, 500);
57
87
  };
58
88
  }
59
89
  /**
60
- * Express/Nest 既定の未マッチルート 404 body を返す `notFound` ハンドラ。
61
- * `app.notFound(nestNotFoundHandler)` で使う(receptray/winecode は未実装の parity ギャップ)。
90
+ * Hono `notFound` handler that returns the canonical Express/NestJS unmatched-route 404 body.
91
+ *
92
+ * @remarks
93
+ * Produces `{ message: "Cannot <METHOD> <path>", error: 'Not Found', statusCode: 404 }`, matching the
94
+ * NestJS default 404 response so unmatched routes stay byte-identical.
95
+ *
96
+ * @param c - The Hono request context for the unmatched route.
97
+ * @returns A 404 JSON response.
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * app.notFound(nestNotFoundHandler);
102
+ * ```
62
103
  */
63
104
  export function nestNotFoundHandler(c) {
64
105
  return c.json({ message: `Cannot ${c.req.method} ${new URL(c.req.url).pathname}`, error: 'Not Found', statusCode: 404 }, 404);
@@ -1,11 +1,31 @@
1
1
  import type { Context } from 'hono';
2
- /** クライアントの IP / UA(NestJS の @UserProtocol デコレータ相当)。 */
2
+ /**
3
+ * The client's network identity: IP address and user agent.
4
+ *
5
+ * @remarks
6
+ * Equivalent to the data a NestJS `@UserProtocol` decorator would expose, so a Hono app can persist the
7
+ * same client metadata. Both fields are nullable to map directly onto nullable database columns.
8
+ */
3
9
  export interface IUserProtocol {
10
+ /** Client IP address, or `null` when no source header is present. */
4
11
  ipAddress: string | null;
12
+ /** Client user-agent string, or `null` when the `User-Agent` header is absent. */
5
13
  userAgent: string | null;
6
14
  }
7
15
  /**
8
- * Hono Context からクライアント IP / UA を取得する。Cloudflare は実 IP `CF-Connecting-IP` に入れる
9
- * (`X-Forwarded-For` はフォールバック)。未取得は null(DB の nullable カラムにそのまま入る)。
16
+ * Read the client's IP address and user agent from the Hono request context.
17
+ *
18
+ * @remarks
19
+ * On Cloudflare the real client IP is provided in `CF-Connecting-IP`, with `X-Forwarded-For` used as a
20
+ * fallback. Missing values resolve to `null` so they map cleanly onto nullable storage.
21
+ *
22
+ * @param c - The Hono request context to read headers from.
23
+ * @returns The client's IP address and user agent for the current request.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const { ipAddress, userAgent } = getUserProtocol(c);
28
+ * await auditLog.insert({ ipAddress, userAgent });
29
+ * ```
10
30
  */
11
31
  export declare const getUserProtocol: (c: Context) => IUserProtocol;
@@ -1,6 +1,18 @@
1
1
  /**
2
- * Hono Context からクライアント IP / UA を取得する。Cloudflare は実 IP `CF-Connecting-IP` に入れる
3
- * (`X-Forwarded-For` はフォールバック)。未取得は null(DB の nullable カラムにそのまま入る)。
2
+ * Read the client's IP address and user agent from the Hono request context.
3
+ *
4
+ * @remarks
5
+ * On Cloudflare the real client IP is provided in `CF-Connecting-IP`, with `X-Forwarded-For` used as a
6
+ * fallback. Missing values resolve to `null` so they map cleanly onto nullable storage.
7
+ *
8
+ * @param c - The Hono request context to read headers from.
9
+ * @returns The client's IP address and user agent for the current request.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const { ipAddress, userAgent } = getUserProtocol(c);
14
+ * await auditLog.insert({ ipAddress, userAgent });
15
+ * ```
4
16
  */
5
17
  export const getUserProtocol = (c) => ({
6
18
  ipAddress: c.req.header('cf-connecting-ip') ?? c.req.header('x-forwarded-for') ?? null,
package/dist/index.d.ts CHANGED
@@ -1,3 +1,14 @@
1
+ /**
2
+ * `@rdlabo/workers-hono-kit` — infrastructure-layer helpers for Hono on Cloudflare Workers.
3
+ *
4
+ * This package collects reusable, configuration-injected building blocks (HTTP middleware,
5
+ * caching, Stripe, Drizzle helpers, AI Gateway, AWS/Firebase integrations) that can be shared
6
+ * across services. Domain logic, database schemas, and application-specific behavior are
7
+ * intentionally left to the consuming application; only generic infrastructure that can be made
8
+ * reusable through dependency/configuration injection lives here.
9
+ *
10
+ * @packageDocumentation
11
+ */
1
12
  export { finalizeResponse } from './middleware/finalize-response.js';
2
13
  export { validate, createSentryValidate } from './middleware/validation.js';
3
14
  export type { ValidateOptions, ValidationTarget, ZodErrorLike, SentryLike, SentryScopeLike, } from './middleware/validation.js';
package/dist/index.js CHANGED
@@ -1,6 +1,14 @@
1
- // @rdlabo/workers-hono-kit — フリート共通のインフラ層ヘルパ(receptray / winecode / foodlabel)。
2
- // ドメイン・DB・各 repo 固有の parity 差異(auth エラー status/body、secretId、Secret スキーマ)は
3
- // 各 repo 側に残し、ここには「設定注入で汎用化できるインフラ」だけを置く。
1
+ /**
2
+ * `@rdlabo/workers-hono-kit` infrastructure-layer helpers for Hono on Cloudflare Workers.
3
+ *
4
+ * This package collects reusable, configuration-injected building blocks (HTTP middleware,
5
+ * caching, Stripe, Drizzle helpers, AI Gateway, AWS/Firebase integrations) that can be shared
6
+ * across services. Domain logic, database schemas, and application-specific behavior are
7
+ * intentionally left to the consuming application; only generic infrastructure that can be made
8
+ * reusable through dependency/configuration injection lives here.
9
+ *
10
+ * @packageDocumentation
11
+ */
4
12
  // middleware
5
13
  export { finalizeResponse } from './middleware/finalize-response.js';
6
14
  export { validate, createSentryValidate } from './middleware/validation.js';
@@ -1,36 +1,97 @@
1
1
  import type { Context, Env, MiddlewareHandler } from 'hono';
2
2
  import type { ContentfulStatusCode } from 'hono/utils/http-status';
3
3
  import type { AppInfo } from '../http/app-info.js';
4
+ /**
5
+ * Configuration for {@link createAuthMiddleware}.
6
+ *
7
+ * @typeParam E - The Hono `Env` (bindings/variables) of the application.
8
+ * @typeParam Verified - The value produced by {@link AuthMiddlewareOptions.verify} (e.g. a decoded token or user record).
9
+ * @typeParam Id - The resolved user identifier type.
10
+ */
4
11
  export interface AuthMiddlewareOptions<E extends Env, Verified, Id = unknown> {
5
- /** ID トークンを載せるヘッダ。既定 `'x-amz-security-token'`(フリート共通)。 */
12
+ /** Header carrying the ID token. Defaults to `'x-amz-security-token'`. */
6
13
  tokenHeader?: string;
7
- /** 生トークンを検証して record/decoded を返す。無効なら throw / reject すること。 */
14
+ /**
15
+ * Verify the raw token and return the decoded value or user record.
16
+ *
17
+ * @param token - The raw token read from {@link AuthMiddlewareOptions.tokenHeader} (empty string if absent).
18
+ * @param c - The current Hono context.
19
+ * @returns The verified value passed to {@link AuthMiddlewareOptions.resolveUserId}/{@link AuthMiddlewareOptions.setContext}.
20
+ * @throws If the token is invalid; rejecting/throwing triggers the failure path.
21
+ */
8
22
  verify: (token: string, c: Context<E>) => Promise<Verified>;
9
23
  /**
10
- * DB userId を解決(必要なら新規作成)する。**省略すると token-only**(検証のみ・login 用)になる。
11
- * create-on-miss(`getUserIdFromFirebase(...).catch(() => createUser(...))`)は repo 側でここに合成する。
24
+ * Resolve the database user id (creating the user if necessary).
25
+ *
26
+ * @remarks
27
+ * Omit this to run in **token-only** mode (verification only, e.g. for login). Create-on-miss
28
+ * behavior (such as `getUserId(...).catch(() => createUser(...))`) should be composed here by the
29
+ * caller.
30
+ *
31
+ * @param verified - The value returned by {@link AuthMiddlewareOptions.verify}.
32
+ * @param c - The current Hono context.
33
+ * @param appInfo - The resolved application info for the request.
34
+ * @returns The resolved user id.
12
35
  */
13
36
  resolveUserId?: (verified: Verified, c: Context<E>, appInfo: AppInfo) => Promise<Id>;
14
- /** 検証結果を c.var に載せる。repo 固有の var 名(`decodedToken` / `userRecord` / `userProtocol` 等)を注入する。 */
37
+ /**
38
+ * Store the verification result on the context variables.
39
+ *
40
+ * @remarks
41
+ * Inject the application-specific variable names here (e.g. `decodedToken`, `userRecord`, `userProtocol`).
42
+ *
43
+ * @param c - The current Hono context.
44
+ * @param data - The verified value, resolved app info, and (when available) the user id.
45
+ */
15
46
  setContext: (c: Context<E>, data: {
16
47
  verified: Verified;
17
48
  appInfo: AppInfo;
18
49
  userId?: Id;
19
50
  }) => void;
20
51
  /**
21
- * 失敗時の挙動。既定は `throw new HTTPException(failureStatus, { message: failureMessage })`
22
- * (foodlabel/receptray と同形)。**winecode は `c.json(BODY, n)` を返す**ため上書きする。
52
+ * Override the failure behavior.
53
+ *
54
+ * @remarks
55
+ * Defaults to `throw new HTTPException(failureStatus, { message: failureMessage })`. Provide this to
56
+ * return a custom `Response` instead (e.g. `c.json(body, status)`).
57
+ *
58
+ * @param err - The error thrown during verification/resolution.
59
+ * @param c - The current Hono context.
60
+ * @returns The failure response to send.
23
61
  */
24
62
  onFailure?: (err: unknown, c: Context<E>) => Response;
25
- /** 既定 onFailure status。既定 `403`(token-only 401 等は repo が上書き)。 */
63
+ /** Status used by the default `onFailure`. Defaults to `403`. */
26
64
  failureStatus?: ContentfulStatusCode;
27
- /** 既定 onFailure message。既定 `'Forbidden resource'`。 */
65
+ /** Message used by the default `onFailure`. Defaults to `'Forbidden resource'`. */
28
66
  failureMessage?: string;
29
67
  }
30
68
  /**
31
- * NestJS AuthGuard / TokenGuard 相当の認証 middleware を作る(フリート共通)。
32
- * スケルトン(ヘッダ読取 → verify → getAppInfo → resolveUserId → setContext、失敗で console.error +
33
- * onFailure)を共有し、repo 固有部分(verify / userId 解決 / var / 失敗レスポンス)だけ注入させる。
34
- * `resolveUserId` を省けば token-only middleware になる。
69
+ * Create an authentication middleware equivalent to a NestJS `AuthGuard` / `TokenGuard`.
70
+ *
71
+ * The middleware runs a fixed skeleton read the token header, `verify`, `getAppInfo`,
72
+ * `resolveUserId`, `setContext`, and on error `console.error` then `onFailure` — while the
73
+ * application injects the variable parts (token verification, user-id resolution, context variable
74
+ * names, and the failure response). Omitting {@link AuthMiddlewareOptions.resolveUserId} yields a
75
+ * token-only middleware.
76
+ *
77
+ * @typeParam E - The Hono `Env` of the application.
78
+ * @typeParam Verified - The value produced by `verify`.
79
+ * @typeParam Id - The resolved user identifier type.
80
+ * @param options - The verification, resolution, and failure hooks; see {@link AuthMiddlewareOptions}.
81
+ * @returns A {@link MiddlewareHandler} that authenticates the request and populates the context.
82
+ * @throws HTTPException From the default failure handler when `onFailure` is not supplied.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const auth = createAuthMiddleware({
87
+ * verify: (token, c) => verifier.verifyIdToken(token),
88
+ * resolveUserId: (decoded) => findUserId(decoded.uid),
89
+ * setContext: (c, { verified, userId }) => {
90
+ * c.set('decodedToken', verified);
91
+ * c.set('userId', userId);
92
+ * },
93
+ * });
94
+ * app.use('/api/*', auth);
95
+ * ```
35
96
  */
36
97
  export declare function createAuthMiddleware<E extends Env = Env, Verified = unknown, Id = unknown>(options: AuthMiddlewareOptions<E, Verified, Id>): MiddlewareHandler<E>;
@@ -1,10 +1,33 @@
1
1
  import { HTTPException } from 'hono/http-exception';
2
2
  import { getAppInfo } from '../http/app-info.js';
3
3
  /**
4
- * NestJS AuthGuard / TokenGuard 相当の認証 middleware を作る(フリート共通)。
5
- * スケルトン(ヘッダ読取 → verify → getAppInfo → resolveUserId → setContext、失敗で console.error +
6
- * onFailure)を共有し、repo 固有部分(verify / userId 解決 / var / 失敗レスポンス)だけ注入させる。
7
- * `resolveUserId` を省けば token-only middleware になる。
4
+ * Create an authentication middleware equivalent to a NestJS `AuthGuard` / `TokenGuard`.
5
+ *
6
+ * The middleware runs a fixed skeleton read the token header, `verify`, `getAppInfo`,
7
+ * `resolveUserId`, `setContext`, and on error `console.error` then `onFailure` — while the
8
+ * application injects the variable parts (token verification, user-id resolution, context variable
9
+ * names, and the failure response). Omitting {@link AuthMiddlewareOptions.resolveUserId} yields a
10
+ * token-only middleware.
11
+ *
12
+ * @typeParam E - The Hono `Env` of the application.
13
+ * @typeParam Verified - The value produced by `verify`.
14
+ * @typeParam Id - The resolved user identifier type.
15
+ * @param options - The verification, resolution, and failure hooks; see {@link AuthMiddlewareOptions}.
16
+ * @returns A {@link MiddlewareHandler} that authenticates the request and populates the context.
17
+ * @throws HTTPException From the default failure handler when `onFailure` is not supplied.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const auth = createAuthMiddleware({
22
+ * verify: (token, c) => verifier.verifyIdToken(token),
23
+ * resolveUserId: (decoded) => findUserId(decoded.uid),
24
+ * setContext: (c, { verified, userId }) => {
25
+ * c.set('decodedToken', verified);
26
+ * c.set('userId', userId);
27
+ * },
28
+ * });
29
+ * app.use('/api/*', auth);
30
+ * ```
8
31
  */
9
32
  export function createAuthMiddleware(options) {
10
33
  const { tokenHeader = 'x-amz-security-token', verify, resolveUserId, setContext, onFailure, failureStatus = 403, failureMessage = 'Forbidden resource', } = options;
@@ -17,8 +40,9 @@ export function createAuthMiddleware(options) {
17
40
  setContext(c, { verified, appInfo, userId });
18
41
  }
19
42
  catch (e) {
20
- // Nest guard false → ForbiddenException('Forbidden resource')。原因をログし、既定では throw して
21
- // app.onError Nest body を描かせる(repo onFailure return 形に上書き可能)。
43
+ // Equivalent to a guard returning false → ForbiddenException('Forbidden resource'). Log the
44
+ // cause and, by default, throw so the app's onError renders the error body (callers can
45
+ // override with onFailure to return a custom response instead).
22
46
  console.error(e);
23
47
  if (onFailure) {
24
48
  return onFailure(e, c);
@@ -1,2 +1,32 @@
1
1
  import type { MiddlewareHandler } from 'hono';
2
+ /**
3
+ * Create a Hono middleware that finalizes responses for byte-parity with an Express/Nest backend.
4
+ *
5
+ * After the downstream handler runs, it performs two adjustments:
6
+ *
7
+ * 1. **JSON charset**: Express's `res.json` emits `application/json; charset=utf-8`, whereas Hono's
8
+ * `c.json` emits a bare `application/json`. A bare `application/json` content type is rewritten
9
+ * to include `; charset=utf-8`.
10
+ * 2. **Weak ETag**: An Express `etag`-package compatible weak ETag is added, matching the format an
11
+ * Express/Nest backend applies to responses by default. See {@link weakEtag} for the exact format.
12
+ *
13
+ * Server-Sent Events (`text/event-stream`) are skipped entirely because the stream cannot be
14
+ * buffered. ETag generation is also skipped for `204`/`304` responses, responses that already carry
15
+ * an `etag` header, and responses without a body.
16
+ *
17
+ * @returns A {@link MiddlewareHandler} that rewrites the response headers (and body, when an ETag
18
+ * must be computed) in place.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { Hono } from 'hono';
23
+ * import { finalizeResponse } from '@rdlabo/workers-hono-kit';
24
+ *
25
+ * const app = new Hono();
26
+ * app.use('*', finalizeResponse());
27
+ * app.get('/users', (c) => c.json({ ok: true }));
28
+ * // → Content-Type: application/json; charset=utf-8
29
+ * // → ETag: W/"b-..." (b = 0xb = 11 bytes, the length of `{"ok":true}`)
30
+ * ```
31
+ */
2
32
  export declare function finalizeResponse(): MiddlewareHandler;