@shaferllc/keel 0.59.0 → 0.68.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 (166) hide show
  1. package/AGENTS.md +167 -0
  2. package/README.md +30 -1
  3. package/bin/keel-mcp.mjs +9 -0
  4. package/dist/core/application.d.ts +5 -5
  5. package/dist/core/application.js +14 -2
  6. package/dist/core/auth.d.ts +47 -0
  7. package/dist/core/auth.js +77 -0
  8. package/dist/core/authorization.d.ts +9 -1
  9. package/dist/core/authorization.js +22 -2
  10. package/dist/core/cache.d.ts +82 -5
  11. package/dist/core/cache.js +181 -23
  12. package/dist/core/cli/stubs.d.ts +12 -0
  13. package/dist/core/cli/stubs.js +120 -0
  14. package/dist/core/container.d.ts +20 -0
  15. package/dist/core/container.js +52 -0
  16. package/dist/core/cors.d.ts +29 -0
  17. package/dist/core/cors.js +72 -0
  18. package/dist/core/crypto.d.ts +40 -4
  19. package/dist/core/crypto.js +66 -6
  20. package/dist/core/csrf.d.ts +25 -0
  21. package/dist/core/csrf.js +78 -0
  22. package/dist/core/database.d.ts +49 -4
  23. package/dist/core/database.js +89 -21
  24. package/dist/core/events.d.ts +129 -5
  25. package/dist/core/events.js +165 -7
  26. package/dist/core/health.d.ts +141 -0
  27. package/dist/core/health.js +226 -0
  28. package/dist/core/helpers.d.ts +15 -3
  29. package/dist/core/helpers.js +23 -3
  30. package/dist/core/index.d.ts +33 -18
  31. package/dist/core/index.js +16 -8
  32. package/dist/core/lock.d.ts +139 -0
  33. package/dist/core/lock.js +215 -0
  34. package/dist/core/logger.d.ts +82 -4
  35. package/dist/core/logger.js +141 -23
  36. package/dist/core/mail.d.ts +128 -7
  37. package/dist/core/mail.js +264 -16
  38. package/dist/core/model.d.ts +2 -0
  39. package/dist/core/model.js +16 -14
  40. package/dist/core/provider.d.ts +7 -0
  41. package/dist/core/provider.js +7 -0
  42. package/dist/core/queue.d.ts +134 -9
  43. package/dist/core/queue.js +304 -14
  44. package/dist/core/rate-limit.js +3 -0
  45. package/dist/core/relations.js +13 -13
  46. package/dist/core/request.d.ts +26 -0
  47. package/dist/core/request.js +77 -0
  48. package/dist/core/shield.d.ts +39 -0
  49. package/dist/core/shield.js +60 -0
  50. package/dist/core/social.d.ts +173 -0
  51. package/dist/core/social.js +337 -0
  52. package/dist/core/storage.d.ts +159 -6
  53. package/dist/core/storage.js +287 -7
  54. package/dist/core/tokens.d.ts +74 -0
  55. package/dist/core/tokens.js +155 -0
  56. package/dist/db/d1.d.ts +32 -0
  57. package/dist/db/d1.js +26 -0
  58. package/dist/db/libsql.d.ts +29 -0
  59. package/dist/db/libsql.js +32 -0
  60. package/dist/db/pg.d.ts +29 -0
  61. package/dist/db/pg.js +33 -0
  62. package/dist/mcp/server.d.ts +19 -0
  63. package/dist/mcp/server.js +355 -0
  64. package/docs/ai-manifest.json +2472 -0
  65. package/docs/ai.md +128 -0
  66. package/docs/architecture.md +331 -0
  67. package/docs/authentication.md +453 -0
  68. package/docs/authorization.md +167 -0
  69. package/docs/broadcasting.md +137 -0
  70. package/docs/broker.md +500 -0
  71. package/docs/cache.md +558 -0
  72. package/docs/configuration.md +311 -0
  73. package/docs/console.md +356 -0
  74. package/docs/container.md +467 -0
  75. package/docs/controllers.md +265 -0
  76. package/docs/cors.md +51 -0
  77. package/docs/database.md +530 -0
  78. package/docs/debugging.md +129 -0
  79. package/docs/decorators.md +127 -0
  80. package/docs/errors.md +395 -0
  81. package/docs/events.md +496 -0
  82. package/docs/examples/architecture-app.ts +27 -0
  83. package/docs/examples/authentication.ts +61 -0
  84. package/docs/examples/authorization.ts +79 -0
  85. package/docs/examples/broadcasting.ts +60 -0
  86. package/docs/examples/broker-cache-validate.ts +34 -0
  87. package/docs/examples/broker-fault-tolerance.ts +29 -0
  88. package/docs/examples/broker-middleware.ts +27 -0
  89. package/docs/examples/broker.ts +203 -0
  90. package/docs/examples/cache.ts +222 -0
  91. package/docs/examples/configuration.ts +81 -0
  92. package/docs/examples/container.ts +134 -0
  93. package/docs/examples/controllers.ts +86 -0
  94. package/docs/examples/database.ts +118 -0
  95. package/docs/examples/debugging.ts +41 -0
  96. package/docs/examples/decorators.ts +40 -0
  97. package/docs/examples/errors.ts +121 -0
  98. package/docs/examples/events.ts +204 -0
  99. package/docs/examples/factories.ts +84 -0
  100. package/docs/examples/hashing.ts +71 -0
  101. package/docs/examples/health.ts +94 -0
  102. package/docs/examples/helpers.ts +171 -0
  103. package/docs/examples/hooks.ts +54 -0
  104. package/docs/examples/inertia.ts +81 -0
  105. package/docs/examples/locks.ts +120 -0
  106. package/docs/examples/logger.ts +92 -0
  107. package/docs/examples/mail.ts +160 -0
  108. package/docs/examples/middleware.ts +119 -0
  109. package/docs/examples/migrations.ts +126 -0
  110. package/docs/examples/models.ts +239 -0
  111. package/docs/examples/notification.ts +124 -0
  112. package/docs/examples/providers.ts +123 -0
  113. package/docs/examples/queues.ts +254 -0
  114. package/docs/examples/rate-limiting.ts +42 -0
  115. package/docs/examples/redis.ts +99 -0
  116. package/docs/examples/request-response.ts +197 -0
  117. package/docs/examples/routing.ts +186 -0
  118. package/docs/examples/scheduling.ts +62 -0
  119. package/docs/examples/sessions.ts +102 -0
  120. package/docs/examples/static-files.ts +63 -0
  121. package/docs/examples/storage.ts +132 -0
  122. package/docs/examples/templates.ts +58 -0
  123. package/docs/examples/testing.ts +66 -0
  124. package/docs/examples/transformer.ts +141 -0
  125. package/docs/examples/transformers.ts +49 -0
  126. package/docs/examples/url-builder.ts +86 -0
  127. package/docs/examples/validation.ts +102 -0
  128. package/docs/examples/views.tsx +62 -0
  129. package/docs/examples/vite.ts +106 -0
  130. package/docs/factories.md +166 -0
  131. package/docs/getting-started.md +290 -0
  132. package/docs/hashing.md +259 -0
  133. package/docs/health.md +225 -0
  134. package/docs/helpers.md +347 -0
  135. package/docs/hono.md +186 -0
  136. package/docs/hooks.md +118 -0
  137. package/docs/inertia.md +241 -0
  138. package/docs/locks.md +323 -0
  139. package/docs/logger.md +290 -0
  140. package/docs/mail.md +678 -0
  141. package/docs/middleware.md +425 -0
  142. package/docs/migrations.md +476 -0
  143. package/docs/models.md +810 -0
  144. package/docs/notifications.md +474 -0
  145. package/docs/providers.md +363 -0
  146. package/docs/queues.md +679 -0
  147. package/docs/rate-limiting.md +155 -0
  148. package/docs/redis.md +178 -0
  149. package/docs/request-response.md +953 -0
  150. package/docs/routing.md +804 -0
  151. package/docs/scheduling.md +110 -0
  152. package/docs/security.md +85 -0
  153. package/docs/sessions.md +354 -0
  154. package/docs/social-auth.md +174 -0
  155. package/docs/static-files.md +211 -0
  156. package/docs/storage.md +450 -0
  157. package/docs/templates.md +315 -0
  158. package/docs/testing.md +125 -0
  159. package/docs/transformers.md +381 -0
  160. package/docs/url-builder.md +295 -0
  161. package/docs/validation.md +288 -0
  162. package/docs/views.md +267 -0
  163. package/docs/vite.md +434 -0
  164. package/llms-full.txt +17694 -0
  165. package/llms.txt +116 -0
  166. package/package.json +38 -7
package/docs/logger.md ADDED
@@ -0,0 +1,290 @@
1
+ # Logger
2
+
3
+ A small leveled logger. It writes **structured JSON** by default — one line per
4
+ event, ready for log aggregators — and pretty single-line output in debug. Reach
5
+ it with the global `logger()` helper.
6
+
7
+ ## Logging
8
+
9
+ ```ts
10
+ import { logger } from "@shaferllc/keel/core";
11
+
12
+ logger().info("user registered", { userId: user.id });
13
+ logger().warn("cache miss", { key });
14
+ logger().error("payment failed", { orderId, error: String(err) });
15
+ logger().debug("query", { sql, ms });
16
+ ```
17
+
18
+ The second argument is structured context — it's merged into the log line, not
19
+ string-concatenated, so it stays queryable:
20
+
21
+ ```json
22
+ {"level":"info","time":"2026-07-10T…","msg":"user registered","userId":42}
23
+ ```
24
+
25
+ Every line carries three reserved keys — `level`, `time` (an ISO-8601 stamp), and
26
+ `msg` — followed by any bound fields and then the call's `context`. Context is
27
+ spread last, so a context key of `level`, `time`, or `msg` overwrites the reserved
28
+ field; steer clear of those names in your payloads.
29
+
30
+ ## Levels
31
+
32
+ `debug` < `info` < `warn` < `error`. Only events at or above the configured
33
+ level are emitted. Set the threshold via config:
34
+
35
+ ```ts
36
+ // config/logger.ts
37
+ export default { level: env("LOG_LEVEL", "info") };
38
+ ```
39
+
40
+ Under the hood the levels are ordinal (`debug` 10, `info` 20, `warn` 30,
41
+ `error` 40); a line is dropped when its level sits below the threshold. The
42
+ default threshold is `"info"`, so `debug` lines stay silent until you lower it.
43
+
44
+ Pretty output turns on automatically when `app.debug` is true. In pretty mode
45
+ each event is a single human-readable line —
46
+ `[2026-07-10T…] INFO user registered {"userId":42}` — and the writer routes by
47
+ level: `warn` goes to `console.warn`, `error` to `console.error`, everything else
48
+ to `console.log`. In JSON mode every level is written to `console.log`.
49
+
50
+ ## Child loggers
51
+
52
+ Bind fields once (a request id, a job name) and they appear on every line:
53
+
54
+ ```ts
55
+ const log = logger().child({ requestId: request.header("x-request-id") });
56
+ log.info("handling"); // includes requestId
57
+ log.info("done"); // includes requestId
58
+ ```
59
+
60
+ A child inherits its parent's `level` and `pretty` settings and *merges* its
61
+ bindings on top of the parent's — so you can nest them, and a child's field wins
62
+ over a parent's field of the same name. The parent is untouched; `child()`
63
+ returns a fresh `Logger`.
64
+
65
+ ```ts
66
+ const base = logger().child({ service: "billing" });
67
+ const job = base.child({ jobId }); // { service, jobId } on every line
68
+ ```
69
+
70
+ ## Standing up a logger yourself
71
+
72
+ The framework binds one `Logger` for you, but the class is a plain object you can
73
+ construct directly — handy in a script or a test:
74
+
75
+ ```ts
76
+ import { Logger } from "@shaferllc/keel/core";
77
+
78
+ const log = new Logger({ level: "debug", pretty: true, bindings: { env: "dev" } });
79
+ log.debug("boot", { pid: 1 });
80
+ ```
81
+
82
+ With no options it defaults to `level: "info"`, `pretty: false`, and no bindings.
83
+
84
+ ## Per-request logging
85
+
86
+ `requestLogger()` is a built-in middleware that binds a **child logger with a
87
+ generated `reqId` to each request**, so every log line within a request
88
+ correlates — Fastify's `request.log`. Install it in your HTTP kernel, then reach
89
+ the request's logger anywhere with `requestLog()`:
90
+
91
+ ```ts
92
+ import { requestLogger, requestLog } from "@shaferllc/keel/core";
93
+
94
+ // app/Http/Kernel.ts
95
+ kernel.use(requestLogger());
96
+
97
+ // anywhere in the request — the line carries this request's reqId:
98
+ requestLog().info("charging card", { orderId });
99
+ ```
100
+
101
+ By default it also logs the request start and completion:
102
+
103
+ ```json
104
+ {"level":"info","time":"…","msg":"request","reqId":"…","method":"GET","path":"/orders"}
105
+ {"level":"info","time":"…","msg":"request completed","reqId":"…","status":200,"ms":12.4}
106
+ ```
107
+
108
+ Options: `genReqId(c)` to control id generation, `idHeader` to reuse an incoming
109
+ id (e.g. `"x-request-id"` for distributed tracing), and `logRequests: false` to
110
+ skip the automatic start/completion lines. Outside a request (or without the
111
+ middleware), `requestLog()` falls back to the base `logger()`.
112
+
113
+ ## Redaction
114
+
115
+ Keep secrets out of your logs with `redact` — top-level keys or dot paths. Matched
116
+ values are replaced with `"[redacted]"`; the original object is never mutated:
117
+
118
+ ```ts
119
+ const log = new Logger({
120
+ redact: ["password", "req.headers.authorization"],
121
+ });
122
+
123
+ log.info("login", { user: "ada", password: "s3cret", req: { headers: { authorization: "Bearer x" } } });
124
+ // {"level":"info",…,"user":"ada","password":"[redacted]","req":{"headers":{"authorization":"[redacted]"}}}
125
+ ```
126
+
127
+ Redaction is inherited by child loggers, so a redacting base logger keeps
128
+ per-request loggers safe too.
129
+
130
+ ---
131
+
132
+ ## API reference
133
+
134
+ ### `logger()`
135
+
136
+ `logger(): Logger`
137
+
138
+ Resolves the application's shared `Logger` from the container.
139
+
140
+ ```ts
141
+ import { logger } from "@shaferllc/keel/core";
142
+
143
+ logger().info("ready");
144
+ ```
145
+
146
+ **Notes:** a global helper — no need to thread the logger through your call stack.
147
+ Throws `No Keel application has been bootstrapped…` if called before an
148
+ `Application` exists. Returns the same singleton every call, so `child()` off it
149
+ when you want per-request bindings rather than mutating the shared instance.
150
+
151
+ ### `Logger`
152
+
153
+ The logger itself. The framework binds one for you (reach it with `logger()`),
154
+ but you can also `new Logger(options)` directly.
155
+
156
+ #### `new Logger(options?)`
157
+
158
+ `new Logger(options?: LoggerOptions): Logger`
159
+
160
+ Creates a logger with the given level, format, and bound fields.
161
+
162
+ ```ts
163
+ const log = new Logger({ level: "warn", pretty: true });
164
+ ```
165
+
166
+ **Notes:** `options` defaults to `{}`, which resolves to `level: "info"`,
167
+ `pretty: false`, no bindings. The level is captured at construction — there is no
168
+ setter, so change it by creating a new logger.
169
+
170
+ #### `debug(message, context?)`
171
+
172
+ `debug(message: string, context?: Record<string, unknown>): void`
173
+
174
+ Logs at the `debug` level — the noisiest, off by default.
175
+
176
+ ```ts
177
+ log.debug("cache lookup", { key });
178
+ ```
179
+
180
+ **Notes:** suppressed unless the threshold is `"debug"`. `context` is optional and
181
+ merged into the line after the bound fields.
182
+
183
+ #### `info(message, context?)`
184
+
185
+ `info(message: string, context?: Record<string, unknown>): void`
186
+
187
+ Logs at the `info` level — the default threshold.
188
+
189
+ ```ts
190
+ log.info("user registered", { userId: 42 });
191
+ ```
192
+
193
+ #### `warn(message, context?)`
194
+
195
+ `warn(message: string, context?: Record<string, unknown>): void`
196
+
197
+ Logs at the `warn` level.
198
+
199
+ ```ts
200
+ log.warn("cache miss", { key });
201
+ ```
202
+
203
+ **Notes:** in pretty mode this routes to `console.warn`; in JSON mode, like every
204
+ level, to `console.log`.
205
+
206
+ #### `error(message, context?)`
207
+
208
+ `error(message: string, context?: Record<string, unknown>): void`
209
+
210
+ Logs at the `error` level — the highest, always emitted.
211
+
212
+ ```ts
213
+ log.error("payment failed", { orderId, error: String(err) });
214
+ ```
215
+
216
+ **Notes:** in pretty mode this routes to `console.error`. It does not throw or
217
+ capture stack traces for you — serialize an `Error` into `context` yourself
218
+ (e.g. `error: String(err)` or `err.stack`).
219
+
220
+ #### `child(bindings)`
221
+
222
+ `child(bindings: Record<string, unknown>): Logger`
223
+
224
+ Returns a new logger that carries `bindings` on every line, in addition to the
225
+ parent's.
226
+
227
+ ```ts
228
+ const reqLog = logger().child({ requestId });
229
+ reqLog.info("handling"); // line includes requestId
230
+ ```
231
+
232
+ **Notes:** inherits the parent's `level` and `pretty`; merges bindings over the
233
+ parent's (child wins on key collisions). Chainable — call `child()` on a child.
234
+ The parent is not modified.
235
+
236
+ ### `requestLogger(options?)`
237
+
238
+ `requestLogger(options?: RequestLoggerOptions): MiddlewareHandler`
239
+
240
+ Middleware that binds a `reqId` child logger to each request and (by default)
241
+ logs the request start and completion.
242
+
243
+ ```ts
244
+ kernel.use(requestLogger({ idHeader: "x-request-id" }));
245
+ ```
246
+
247
+ **Notes:** options — `genReqId(c)` (default `crypto.randomUUID()`), `idHeader`
248
+ (reuse an incoming id), `logRequests` (default `true`).
249
+
250
+ ### `requestLog()`
251
+
252
+ `requestLog(): Logger`
253
+
254
+ The current request's child logger (carrying its `reqId`), or the base `logger()`
255
+ outside a request / without the middleware installed.
256
+
257
+ ```ts
258
+ requestLog().info("charging card"); // line carries reqId
259
+ ```
260
+
261
+ ### Interfaces & types
262
+
263
+ #### `LoggerOptions`
264
+
265
+ ```ts
266
+ interface LoggerOptions {
267
+ level?: LogLevel; // minimum level to emit; default "info"
268
+ pretty?: boolean; // single-line human output; default false
269
+ bindings?: Record<string, unknown>; // fields merged into every line
270
+ }
271
+ ```
272
+
273
+ Passed to `new Logger()` (and carried forward by `child()`). Use it to set the
274
+ threshold, switch to pretty output, and attach ambient fields.
275
+
276
+ ```ts
277
+ const log = new Logger({ level: "debug", pretty: true, bindings: { app: "api" } });
278
+ ```
279
+
280
+ #### `LogLevel`
281
+
282
+ `type LogLevel = "debug" | "info" | "warn" | "error"`
283
+
284
+ The four severity levels, in ascending order. Used for the `level` option and
285
+ selected implicitly by each method.
286
+
287
+ ```ts
288
+ const threshold: LogLevel = "warn";
289
+ new Logger({ level: threshold });
290
+ ```