@shaferllc/keel 0.66.0 → 0.74.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 (239) hide show
  1. package/AGENTS.md +169 -0
  2. package/README.md +44 -6
  3. package/bin/keel-mcp.mjs +9 -0
  4. package/dist/api/api.config.stub +9 -0
  5. package/dist/api/config.d.ts +13 -0
  6. package/dist/api/config.js +14 -0
  7. package/dist/api/index.d.ts +16 -0
  8. package/dist/api/index.js +13 -0
  9. package/dist/api/provider.d.ts +10 -0
  10. package/dist/api/provider.js +17 -0
  11. package/dist/api/query.d.ts +35 -0
  12. package/dist/api/query.js +42 -0
  13. package/dist/api/resource.d.ts +91 -0
  14. package/dist/api/resource.js +188 -0
  15. package/dist/core/application.d.ts +5 -5
  16. package/dist/core/application.js +8 -2
  17. package/dist/core/cache.d.ts +81 -5
  18. package/dist/core/cache.js +188 -23
  19. package/dist/core/cli/stubs.d.ts +26 -0
  20. package/dist/core/cli/stubs.js +225 -0
  21. package/dist/core/console-prompt.d.ts +79 -0
  22. package/dist/core/console-prompt.js +239 -0
  23. package/dist/core/console-ui.d.ts +96 -0
  24. package/dist/core/console-ui.js +187 -0
  25. package/dist/core/console.d.ts +188 -0
  26. package/dist/core/console.js +395 -0
  27. package/dist/core/database.d.ts +70 -1
  28. package/dist/core/database.js +174 -15
  29. package/dist/core/env.d.ts +96 -0
  30. package/dist/core/env.js +140 -0
  31. package/dist/core/events.d.ts +129 -5
  32. package/dist/core/events.js +165 -7
  33. package/dist/core/health.d.ts +141 -0
  34. package/dist/core/health.js +226 -0
  35. package/dist/core/helpers.d.ts +9 -3
  36. package/dist/core/helpers.js +11 -3
  37. package/dist/core/http/kernel.d.ts +2 -0
  38. package/dist/core/http/kernel.js +48 -0
  39. package/dist/core/http/router.d.ts +5 -5
  40. package/dist/core/http/router.js +5 -5
  41. package/dist/core/i18n.d.ts +162 -0
  42. package/dist/core/i18n.js +472 -0
  43. package/dist/core/index.d.ts +39 -13
  44. package/dist/core/index.js +19 -6
  45. package/dist/core/instrumentation.d.ts +113 -0
  46. package/dist/core/instrumentation.js +52 -0
  47. package/dist/core/lock.d.ts +139 -0
  48. package/dist/core/lock.js +215 -0
  49. package/dist/core/logger.d.ts +89 -4
  50. package/dist/core/logger.js +167 -22
  51. package/dist/core/mail.d.ts +128 -7
  52. package/dist/core/mail.js +264 -16
  53. package/dist/core/notification.js +10 -1
  54. package/dist/core/package.d.ts +120 -0
  55. package/dist/core/package.js +169 -0
  56. package/dist/core/pages.d.ts +108 -0
  57. package/dist/core/pages.js +199 -0
  58. package/dist/core/queue.d.ts +134 -9
  59. package/dist/core/queue.js +325 -14
  60. package/dist/core/repl.d.ts +33 -0
  61. package/dist/core/repl.js +88 -0
  62. package/dist/core/scheduler.js +6 -0
  63. package/dist/core/social.d.ts +4 -4
  64. package/dist/core/social.js +4 -4
  65. package/dist/core/storage.d.ts +159 -6
  66. package/dist/core/storage.js +299 -7
  67. package/dist/core/telemetry.d.ts +208 -0
  68. package/dist/core/telemetry.js +383 -0
  69. package/dist/core/template.d.ts +2 -3
  70. package/dist/core/template.js +2 -3
  71. package/dist/core/testing.d.ts +170 -1
  72. package/dist/core/testing.js +504 -2
  73. package/dist/db/d1.js +13 -0
  74. package/dist/db/pg.d.ts +13 -0
  75. package/dist/db/pg.js +46 -4
  76. package/dist/mcp/server.d.ts +19 -0
  77. package/dist/mcp/server.js +355 -0
  78. package/dist/openapi/config.d.ts +28 -0
  79. package/dist/openapi/config.js +25 -0
  80. package/dist/openapi/doc.d.ts +40 -0
  81. package/dist/openapi/doc.js +20 -0
  82. package/dist/openapi/export.d.ts +8 -0
  83. package/dist/openapi/export.js +19 -0
  84. package/dist/openapi/gate.d.ts +15 -0
  85. package/dist/openapi/gate.js +27 -0
  86. package/dist/openapi/index.d.ts +19 -0
  87. package/dist/openapi/index.js +15 -0
  88. package/dist/openapi/openapi.config.stub +29 -0
  89. package/dist/openapi/provider.d.ts +18 -0
  90. package/dist/openapi/provider.js +35 -0
  91. package/dist/openapi/routes.d.ts +9 -0
  92. package/dist/openapi/routes.js +23 -0
  93. package/dist/openapi/spec.d.ts +23 -0
  94. package/dist/openapi/spec.js +132 -0
  95. package/dist/openapi/ui.d.ts +8 -0
  96. package/dist/openapi/ui.js +31 -0
  97. package/dist/openapi/zod.d.ts +12 -0
  98. package/dist/openapi/zod.js +46 -0
  99. package/dist/watch/config.d.ts +33 -0
  100. package/dist/watch/config.js +38 -0
  101. package/dist/watch/entry.d.ts +53 -0
  102. package/dist/watch/entry.js +105 -0
  103. package/dist/watch/gate.d.ts +20 -0
  104. package/dist/watch/gate.js +32 -0
  105. package/dist/watch/index.d.ts +21 -0
  106. package/dist/watch/index.js +17 -0
  107. package/dist/watch/migration.d.ts +7 -0
  108. package/dist/watch/migration.js +20 -0
  109. package/dist/watch/provider.d.ts +22 -0
  110. package/dist/watch/provider.js +58 -0
  111. package/dist/watch/prune.d.ts +11 -0
  112. package/dist/watch/prune.js +20 -0
  113. package/dist/watch/recorder.d.ts +24 -0
  114. package/dist/watch/recorder.js +39 -0
  115. package/dist/watch/routes.d.ts +13 -0
  116. package/dist/watch/routes.js +55 -0
  117. package/dist/watch/store.d.ts +54 -0
  118. package/dist/watch/store.js +158 -0
  119. package/dist/watch/ui/dist/watch.css +1 -0
  120. package/dist/watch/ui/dist/watch.js +555 -0
  121. package/dist/watch/ui-shell.d.ts +12 -0
  122. package/dist/watch/ui-shell.js +24 -0
  123. package/dist/watch/watch.config.stub +47 -0
  124. package/dist/watch/watchers.d.ts +12 -0
  125. package/dist/watch/watchers.js +156 -0
  126. package/docs/ai-manifest.json +3206 -0
  127. package/docs/ai.md +128 -0
  128. package/docs/api-resources.md +118 -0
  129. package/docs/architecture.md +331 -0
  130. package/docs/authentication.md +453 -0
  131. package/docs/authorization.md +167 -0
  132. package/docs/broadcasting.md +137 -0
  133. package/docs/broker.md +500 -0
  134. package/docs/cache.md +558 -0
  135. package/docs/configuration.md +385 -0
  136. package/docs/console.md +536 -0
  137. package/docs/container.md +467 -0
  138. package/docs/controllers.md +265 -0
  139. package/docs/cors.md +51 -0
  140. package/docs/database.md +631 -0
  141. package/docs/debugging.md +129 -0
  142. package/docs/decorators.md +127 -0
  143. package/docs/errors.md +395 -0
  144. package/docs/events.md +496 -0
  145. package/docs/examples/architecture-app.ts +27 -0
  146. package/docs/examples/authentication.ts +61 -0
  147. package/docs/examples/authorization.ts +79 -0
  148. package/docs/examples/broadcasting.ts +60 -0
  149. package/docs/examples/broker-cache-validate.ts +34 -0
  150. package/docs/examples/broker-fault-tolerance.ts +29 -0
  151. package/docs/examples/broker-middleware.ts +27 -0
  152. package/docs/examples/broker.ts +203 -0
  153. package/docs/examples/cache.ts +222 -0
  154. package/docs/examples/configuration.ts +121 -0
  155. package/docs/examples/console.ts +134 -0
  156. package/docs/examples/container.ts +134 -0
  157. package/docs/examples/controllers.ts +86 -0
  158. package/docs/examples/database.ts +208 -0
  159. package/docs/examples/debugging.ts +41 -0
  160. package/docs/examples/decorators.ts +40 -0
  161. package/docs/examples/errors.ts +121 -0
  162. package/docs/examples/events.ts +204 -0
  163. package/docs/examples/factories.ts +84 -0
  164. package/docs/examples/hashing.ts +71 -0
  165. package/docs/examples/health.ts +94 -0
  166. package/docs/examples/helpers.ts +171 -0
  167. package/docs/examples/hooks.ts +54 -0
  168. package/docs/examples/i18n.ts +117 -0
  169. package/docs/examples/inertia.ts +81 -0
  170. package/docs/examples/locks.ts +120 -0
  171. package/docs/examples/logger.ts +166 -0
  172. package/docs/examples/mail.ts +263 -0
  173. package/docs/examples/middleware.ts +119 -0
  174. package/docs/examples/migrations.ts +126 -0
  175. package/docs/examples/models.ts +239 -0
  176. package/docs/examples/notification.ts +124 -0
  177. package/docs/examples/pages.ts +82 -0
  178. package/docs/examples/providers.ts +123 -0
  179. package/docs/examples/queues.ts +254 -0
  180. package/docs/examples/rate-limiting.ts +42 -0
  181. package/docs/examples/redis.ts +99 -0
  182. package/docs/examples/request-response.ts +197 -0
  183. package/docs/examples/routing.ts +186 -0
  184. package/docs/examples/scheduling.ts +62 -0
  185. package/docs/examples/sessions.ts +102 -0
  186. package/docs/examples/static-files.ts +63 -0
  187. package/docs/examples/storage.ts +132 -0
  188. package/docs/examples/telemetry.ts +127 -0
  189. package/docs/examples/templates.ts +58 -0
  190. package/docs/examples/testing.ts +215 -0
  191. package/docs/examples/transformer.ts +141 -0
  192. package/docs/examples/transformers.ts +49 -0
  193. package/docs/examples/url-builder.ts +86 -0
  194. package/docs/examples/validation.ts +102 -0
  195. package/docs/examples/views.tsx +62 -0
  196. package/docs/examples/vite.ts +106 -0
  197. package/docs/factories.md +166 -0
  198. package/docs/getting-started.md +290 -0
  199. package/docs/hashing.md +259 -0
  200. package/docs/health.md +225 -0
  201. package/docs/helpers.md +347 -0
  202. package/docs/hono.md +186 -0
  203. package/docs/hooks.md +118 -0
  204. package/docs/i18n.md +302 -0
  205. package/docs/inertia.md +241 -0
  206. package/docs/locks.md +323 -0
  207. package/docs/logger.md +436 -0
  208. package/docs/mail.md +751 -0
  209. package/docs/middleware.md +425 -0
  210. package/docs/migrations.md +476 -0
  211. package/docs/models.md +810 -0
  212. package/docs/notifications.md +474 -0
  213. package/docs/openapi.md +111 -0
  214. package/docs/packages.md +118 -0
  215. package/docs/pages.md +217 -0
  216. package/docs/providers.md +363 -0
  217. package/docs/queues.md +679 -0
  218. package/docs/rate-limiting.md +155 -0
  219. package/docs/redis.md +178 -0
  220. package/docs/request-response.md +953 -0
  221. package/docs/routing.md +804 -0
  222. package/docs/scheduling.md +110 -0
  223. package/docs/security.md +85 -0
  224. package/docs/sessions.md +354 -0
  225. package/docs/social-auth.md +174 -0
  226. package/docs/static-files.md +211 -0
  227. package/docs/storage.md +452 -0
  228. package/docs/telemetry.md +263 -0
  229. package/docs/templates.md +314 -0
  230. package/docs/testing.md +376 -0
  231. package/docs/transformers.md +381 -0
  232. package/docs/url-builder.md +295 -0
  233. package/docs/validation.md +288 -0
  234. package/docs/views.md +267 -0
  235. package/docs/vite.md +434 -0
  236. package/docs/watch.md +118 -0
  237. package/llms-full.txt +19816 -0
  238. package/llms.txt +127 -0
  239. package/package.json +42 -7
@@ -0,0 +1,385 @@
1
+ # Configuration
2
+
3
+ Keel loads configuration from two sources: environment variables (`.env`) and
4
+ config files (`config/*.ts`). Config files read env vars; your app reads config.
5
+
6
+ ## Environment variables
7
+
8
+ `.env` holds environment-specific values and secrets. It ships with:
9
+
10
+ ```
11
+ APP_NAME=Keel
12
+ APP_ENV=local
13
+ APP_DEBUG=true
14
+ APP_URL=http://localhost:3000
15
+ APP_PORT=3000
16
+ ```
17
+
18
+ `.env` is git-ignored. Commit a `.env.example` with safe defaults so teammates
19
+ know what to set.
20
+
21
+ ### The `env()` helper
22
+
23
+ Read env vars with `env()`, which coerces obvious types:
24
+
25
+ ```ts
26
+ import { env } from "@shaferllc/keel/core";
27
+
28
+ env("APP_NAME"); // "Keel"
29
+ env("APP_DEBUG", false); // true (string "true" -> boolean)
30
+ env("APP_PORT", 3000); // 3000 (coerced to number when the fallback is a number)
31
+ env("MISSING", "default"); // "default"
32
+ ```
33
+
34
+ Coercion follows two rules, and they don't behave the same way:
35
+
36
+ - **Booleans are always coerced.** The literal strings `"true"` and `"false"`
37
+ become `true` / `false` regardless of the fallback — even with no fallback at
38
+ all. So `env("APP_DEBUG")` on `APP_DEBUG=true` returns the boolean `true`, not
39
+ the string `"true"`.
40
+ - **Numbers are coerced only when the fallback is a number.** `env("APP_PORT", 3000)`
41
+ returns the number `3000`, but `env("APP_PORT")` returns the *string* `"3000"` —
42
+ without a numeric fallback there's nothing to signal that a number was wanted.
43
+ An empty string is never treated as a number.
44
+
45
+ ```ts
46
+ env("APP_PORT"); // "3000" (string — no numeric fallback)
47
+ env("APP_PORT", 0); // 3000 (number — fallback is numeric)
48
+ env("APP_DEBUG"); // true (boolean, even with no fallback)
49
+ ```
50
+
51
+ The generic defaults to `string`, but the return is asserted to `T` at the
52
+ boundary — the runtime value can be a boolean or number even where the type says
53
+ string. Pass a fallback of the type you expect and the type follows it.
54
+
55
+ Use `env()` **only inside config files**, not scattered through your app. That
56
+ keeps all environment coupling in one layer.
57
+
58
+ ## Validating the environment
59
+
60
+ `env("DATABASE_URL")` hands back whatever is — or isn't — in `process.env`. A
61
+ missing variable is `undefined`, the app boots looking perfectly healthy, and then
62
+ dies on the first request that actually needs it. In production. At night.
63
+
64
+ `defineEnv()` checks the whole environment **at boot** and refuses to start
65
+ otherwise:
66
+
67
+ ```ts
68
+ // config/env.ts
69
+ import { defineEnv, envVar } from "@shaferllc/keel/core";
70
+
71
+ export const env = defineEnv({
72
+ APP_KEY: envVar.string({ required: true, description: "32+ random characters" }),
73
+ PORT: envVar.number({ default: 3000 }),
74
+ NODE_ENV: envVar.enum(["development", "test", "production"], { default: "development" }),
75
+ DATABASE_URL: envVar.url({ required: true }),
76
+ SENTRY_DSN: envVar.string(), // optional
77
+ });
78
+ ```
79
+
80
+ ```ts
81
+ env.PORT; // number — not "3000"
82
+ env.NODE_ENV; // "development" | "test" | "production" — not string
83
+ env.SENTRY_DSN; // string | undefined
84
+ ```
85
+
86
+ The types are **inferred from the rules**. A `number` rule gives you a `number`; an
87
+ `enum` gives you the union, not `string`; anything optional without a default is
88
+ `| undefined`, so you can't forget to handle it.
89
+
90
+ ### It reports every problem at once
91
+
92
+ ```
93
+ The environment is not valid:
94
+
95
+ • APP_KEY is required but not set (32+ random characters).
96
+ • PORT must be a number, got "eighty".
97
+ • NODE_ENV must be one of development, test, production, got "staging".
98
+ • DATABASE_URL must be a valid URL, got "not a url".
99
+
100
+ Set these in your .env (or your host's environment) and start again.
101
+ ```
102
+
103
+ Not the first problem — **all** of them. Fixing a deploy one missing variable per
104
+ restart is its own small hell.
105
+
106
+ ### Rules
107
+
108
+ | Rule | Value | Notes |
109
+ |------|-------|-------|
110
+ | `envVar.string()` | `string` | |
111
+ | `envVar.number()` | `number` | rejects `"eighty"` |
112
+ | `envVar.boolean()` | `boolean` | accepts `true/false/1/0/yes/no/on/off` |
113
+ | `envVar.enum([...])` | the union | typed as the literal union |
114
+ | `envVar.url()` | `string` | must parse as a URL — catches a truncated connection string |
115
+
116
+ Each takes `required`, `default`, `description` (shown in the error, so they know
117
+ what to set), and `validate` for anything else:
118
+
119
+ ```ts
120
+ APP_KEY: envVar.string({
121
+ required: true,
122
+ validate: (value) => (value.length >= 32 ? true : "must be at least 32 characters"),
123
+ });
124
+ ```
125
+
126
+ **An empty string counts as absent.** `PORT=` in a `.env` file is a typo, not a
127
+ deliberate empty port.
128
+
129
+ The returned object is frozen, so nothing can quietly reassign your config at
130
+ runtime.
131
+
132
+ ## Config files
133
+
134
+ Each file in `config/` exports a default object and is loaded under its
135
+ filename. `config/app.ts` becomes the `app` namespace:
136
+
137
+ ```ts
138
+ // config/app.ts
139
+ import { env } from "@shaferllc/keel/core";
140
+
141
+ export default {
142
+ name: env("APP_NAME", "Keel"),
143
+ env: env("APP_ENV", "local"),
144
+ debug: env("APP_DEBUG", true),
145
+ url: env("APP_URL", "http://localhost:3000"),
146
+ port: env("APP_PORT", 3000),
147
+ };
148
+ ```
149
+
150
+ Add more files freely — `config/services.ts`, `config/mail.ts` — and they're
151
+ auto-loaded at boot. No registration needed.
152
+
153
+ ## Reading config
154
+
155
+ The quickest way is the global `config()` helper — no container needed:
156
+
157
+ ```ts
158
+ import { config } from "@shaferllc/keel/core";
159
+
160
+ config("app.name"); // "Keel"
161
+ config("app.port", 3000); // with a fallback
162
+ config("services.stripe.key"); // nested access
163
+ ```
164
+
165
+ It resolves against the active application (registered automatically when the
166
+ `Application` is created). There is a matching `app()` helper that returns the
167
+ container:
168
+
169
+ ```ts
170
+ import { app } from "@shaferllc/keel/core";
171
+
172
+ app().make(SomeService);
173
+ ```
174
+
175
+ Both `config()` and `app()` throw if no application has been bootstrapped yet —
176
+ `config()` reaches the repository *through* `app()`, so the error is the same
177
+ `No Keel application has been bootstrapped…`. In a normal single-app process the
178
+ `Application` constructor registers itself, so this only bites in tests or
179
+ scripts that skip the bootstrap.
180
+
181
+ ### The long form
182
+
183
+ Under the hood, `config()` is sugar for resolving the `Config` repository and
184
+ reading with dot notation. You can still do that explicitly:
185
+
186
+ ```ts
187
+ import { Config, app } from "@shaferllc/keel/core";
188
+
189
+ const config = app().make(Config);
190
+
191
+ config.get("app.name"); // "Keel"
192
+ config.get("app.port", 3000); // with a fallback
193
+ config.get("services.stripe.key"); // nested access
194
+ config.set("app.debug", false); // override at runtime
195
+ config.all(); // the whole tree
196
+ ```
197
+
198
+ Note `app()` is a function — call it, then reach into the container
199
+ (`app().make(...)`), not `app.make(...)`.
200
+
201
+ From within the `Application` there's a shortcut:
202
+
203
+ ```ts
204
+ app().config().get("app.name");
205
+ ```
206
+
207
+ There is **no `has()` method** on `Config`. To check for a key, read it with a
208
+ sentinel fallback and compare, or pass the fallback you'd want anyway:
209
+
210
+ ```ts
211
+ const config = app().make(Config);
212
+ if (config.get("services.stripe.key") !== undefined) {
213
+ // configured
214
+ }
215
+ ```
216
+
217
+ ### Missing keys and fallbacks
218
+
219
+ `get()` walks the key segment by segment. If any segment is missing — or a
220
+ segment isn't an object it can descend into — it returns the fallback (or
221
+ `undefined` when you gave none) rather than throwing:
222
+
223
+ ```ts
224
+ config("services.stripe.key", ""); // "" when unset — never throws
225
+ config("nope.at.all"); // undefined
226
+ ```
227
+
228
+ `set()` creates intermediate objects as it goes, so you can write a deep key
229
+ into an empty tree; and `all()` returns the repository's live object by
230
+ reference — mutating it mutates the config. Treat `all()` as read-only.
231
+
232
+ ## How loading works
233
+
234
+ At boot, `Application`:
235
+
236
+ 1. Loads `.env` via `dotenv`.
237
+ 2. Reads every `*.ts` / `*.js` file in `config/`.
238
+ 3. Registers each under its filename in the `Config` repository.
239
+
240
+ So `config/mail.ts` is reachable at `config('mail.*')` with zero wiring. On
241
+ Workers (no filesystem) skip discovery and pass a config object inline —
242
+ `boot(providers, { discoverConfig: false, config })` — and it's merged under its
243
+ top-level keys the same way. See
244
+ [`src/core/application.ts`](../src/core/application.ts) (`loadConfig`) and
245
+ [`src/core/config.ts`](../src/core/config.ts).
246
+
247
+ ---
248
+
249
+ ## API reference
250
+
251
+ ### `env(key, fallback?)`
252
+
253
+ `env<T = string>(key: string, fallback?: T): T`
254
+
255
+ Reads `process.env[key]`, coercing `"true"`/`"false"` to booleans and numeric
256
+ strings to numbers, with a typed fallback when the variable is unset.
257
+
258
+ ```ts
259
+ const debug = env("APP_DEBUG", false); // boolean
260
+ const port = env("APP_PORT", 3000); // number
261
+ const name = env("APP_NAME", "Keel"); // string
262
+ ```
263
+
264
+ **Notes:** returns the fallback (or `undefined`) when the var is not set.
265
+ Boolean coercion always happens; number coercion happens **only when `fallback`
266
+ is a number** and the raw value is non-empty and numeric. Otherwise the raw
267
+ string is returned. The result is asserted to `T`, so at runtime the value may
268
+ not match the declared type unless your fallback matches the intended type.
269
+
270
+ ### `config(key, fallback?)`
271
+
272
+ `config<T = unknown>(key: string, fallback?: T): T`
273
+
274
+ Global helper: resolves the `Config` repository from the active application and
275
+ reads `key` with dot notation.
276
+
277
+ ```ts
278
+ config("app.name"); // unknown -> narrow or cast
279
+ config<number>("app.port", 3000);
280
+ config("services.stripe.key", "");
281
+ ```
282
+
283
+ **Notes:** thin sugar for `app().make(Config).get(key, fallback)`. Throws
284
+ `No Keel application has been bootstrapped…` if there is no active application.
285
+ Returns the fallback (or `undefined`) for any missing key; never throws on a
286
+ missing key.
287
+
288
+ ### `app()`
289
+
290
+ `app(): Application`
291
+
292
+ Returns the active application container — the one registered by the most recent
293
+ `Application` constructor.
294
+
295
+ ```ts
296
+ app().make(Config);
297
+ app().config().get("app.name");
298
+ ```
299
+
300
+ **Notes:** throws `No Keel application has been bootstrapped…` when no
301
+ `Application` has been created. `app` is a function; call it before reaching into
302
+ the container. In a single-app process the current application is set
303
+ automatically at construction, so you rarely register it by hand.
304
+
305
+ ### `Config`
306
+
307
+ The dot-notation config repository. You normally resolve it from the container
308
+ (`app().make(Config)`) rather than constructing it, but the constructor is public
309
+ for tests and standalone use.
310
+
311
+ #### `new Config(items?)`
312
+
313
+ `new Config(items?: ConfigData)`
314
+
315
+ Creates a repository over the given data (default `{}`).
316
+
317
+ ```ts
318
+ const repo = new Config({ app: { name: "Keel", port: 3000 } });
319
+ repo.get("app.port"); // 3000
320
+ ```
321
+
322
+ **Notes:** the object is held by reference, not cloned — later `set()` calls and
323
+ `all()` operate on the same object you passed in.
324
+
325
+ #### `get(key, fallback?)`
326
+
327
+ `get<T = unknown>(key: string, fallback?: T): T`
328
+
329
+ Reads a value by dot-notation key, descending one segment at a time.
330
+
331
+ ```ts
332
+ repo.get("app.name"); // value
333
+ repo.get("app.port", 3000); // fallback if unset
334
+ repo.get<string>("services.key"); // typed read
335
+ ```
336
+
337
+ **Notes:** returns `fallback` (or `undefined`) if any segment is missing or a
338
+ segment isn't an object it can descend into. Never throws for a missing key. The
339
+ value is asserted to `T` — no runtime validation.
340
+
341
+ #### `set(key, value)`
342
+
343
+ `set(key: string, value: unknown): void`
344
+
345
+ Writes a value at a dot-notation key, creating intermediate objects as needed.
346
+
347
+ ```ts
348
+ repo.set("app.debug", false);
349
+ repo.set("services.stripe.key", "sk_test_…"); // creates `services` on the way
350
+ ```
351
+
352
+ **Notes:** mutates the repository in place. If an intermediate segment exists but
353
+ isn't an object (or is `null`), it's overwritten with a fresh object.
354
+
355
+ #### `all()`
356
+
357
+ `all(): ConfigData`
358
+
359
+ Returns the entire config tree.
360
+
361
+ ```ts
362
+ const tree = repo.all();
363
+ ```
364
+
365
+ **Notes:** returns the live internal object **by reference**, not a copy —
366
+ mutating the result mutates the repository. Treat it as read-only.
367
+
368
+ > There is no `has()` method. Check presence with `get(key) !== undefined`, or
369
+ > pass the fallback you want when the key is absent.
370
+
371
+ ### Interfaces & types
372
+
373
+ #### `ConfigData`
374
+
375
+ `type ConfigData = Record<string, unknown>`
376
+
377
+ The shape of the config tree: a plain string-keyed object, nested arbitrarily.
378
+ Use it to type a config object you build and merge in yourself (for example, the
379
+ inline config passed to `boot({ discoverConfig: false, config })` on Workers).
380
+
381
+ ```ts
382
+ const data: ConfigData = {
383
+ app: { name: "Keel", port: 3000 },
384
+ };
385
+ ```