@zerotal/arch 1.7.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 (160) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +67 -0
  4. package/api-surface.md +283 -0
  5. package/docs/about.md +676 -0
  6. package/docs/admin/actions.md +183 -0
  7. package/docs/admin/auth.md +89 -0
  8. package/docs/admin/dashboard.md +155 -0
  9. package/docs/admin/extending-ui.md +229 -0
  10. package/docs/admin/extending.md +205 -0
  11. package/docs/admin/forms.md +155 -0
  12. package/docs/admin/index.md +144 -0
  13. package/docs/admin/operations.md +224 -0
  14. package/docs/admin/references.md +174 -0
  15. package/docs/admin/resources.md +132 -0
  16. package/docs/admin/structure.md +158 -0
  17. package/docs/admin/tables.md +185 -0
  18. package/docs/admin/testing.md +138 -0
  19. package/docs/ai.md +373 -0
  20. package/docs/application.md +435 -0
  21. package/docs/arch.md +263 -0
  22. package/docs/assets.md +755 -0
  23. package/docs/audit.md +367 -0
  24. package/docs/authentication.md +1000 -0
  25. package/docs/authorization.md +529 -0
  26. package/docs/broadcasting/channels.md +170 -0
  27. package/docs/broadcasting/client.md +108 -0
  28. package/docs/broadcasting/events.md +190 -0
  29. package/docs/broadcasting/index.md +163 -0
  30. package/docs/broadcasting/references.md +84 -0
  31. package/docs/broadcasting/testing.md +132 -0
  32. package/docs/cache.md +387 -0
  33. package/docs/carbon.md +830 -0
  34. package/docs/changelog.md +465 -0
  35. package/docs/client/auth.md +113 -0
  36. package/docs/client/errors.md +139 -0
  37. package/docs/client/files.md +118 -0
  38. package/docs/client/index.md +128 -0
  39. package/docs/client/references.md +58 -0
  40. package/docs/client/requests.md +131 -0
  41. package/docs/client/resilience.md +141 -0
  42. package/docs/client/testing.md +146 -0
  43. package/docs/commands.md +450 -0
  44. package/docs/components.md +2427 -0
  45. package/docs/config-system.md +258 -0
  46. package/docs/container.md +596 -0
  47. package/docs/context.md +579 -0
  48. package/docs/contributing.md +164 -0
  49. package/docs/controllers.md +354 -0
  50. package/docs/conventions.md +466 -0
  51. package/docs/cookies.md +101 -0
  52. package/docs/csrf.md +206 -0
  53. package/docs/database.md +476 -0
  54. package/docs/deployment.md +434 -0
  55. package/docs/devtools.md +1013 -0
  56. package/docs/email-verification.md +320 -0
  57. package/docs/encryption.md +380 -0
  58. package/docs/errors.md +317 -0
  59. package/docs/events.md +420 -0
  60. package/docs/flow/components.md +846 -0
  61. package/docs/flow/decorators.md +458 -0
  62. package/docs/flow/events.md +420 -0
  63. package/docs/flow/forms.md +551 -0
  64. package/docs/flow/index.md +568 -0
  65. package/docs/flow/layouts.md +793 -0
  66. package/docs/flow/lifecycle.md +336 -0
  67. package/docs/flow/pagination.md +402 -0
  68. package/docs/flow/performance.md +262 -0
  69. package/docs/flow/references.md +317 -0
  70. package/docs/flow/routing.md +550 -0
  71. package/docs/flow/testing.md +447 -0
  72. package/docs/getting-started.md +286 -0
  73. package/docs/health.md +269 -0
  74. package/docs/helpers.md +423 -0
  75. package/docs/i18n.md +414 -0
  76. package/docs/index.md +65 -0
  77. package/docs/inertia/build.md +95 -0
  78. package/docs/inertia/devtools.md +197 -0
  79. package/docs/inertia/index.md +267 -0
  80. package/docs/inertia/middleware.md +81 -0
  81. package/docs/inertia/props.md +507 -0
  82. package/docs/inertia/references.md +144 -0
  83. package/docs/inertia/rendering.md +189 -0
  84. package/docs/inertia/ssr.md +102 -0
  85. package/docs/inspirations.md +257 -0
  86. package/docs/lifecycle.md +331 -0
  87. package/docs/lock.md +454 -0
  88. package/docs/logger.md +517 -0
  89. package/docs/media.md +582 -0
  90. package/docs/middleware.md +509 -0
  91. package/docs/migrations.md +529 -0
  92. package/docs/monitor.md +377 -0
  93. package/docs/notifications.md +848 -0
  94. package/docs/orm/casts.md +365 -0
  95. package/docs/orm/factories.md +231 -0
  96. package/docs/orm/index.md +663 -0
  97. package/docs/orm/lifecycle.md +421 -0
  98. package/docs/orm/queries.md +692 -0
  99. package/docs/orm/relationships.md +440 -0
  100. package/docs/orm/serialization.md +251 -0
  101. package/docs/package-development.md +536 -0
  102. package/docs/pagination.md +340 -0
  103. package/docs/password-reset.md +335 -0
  104. package/docs/providers.md +447 -0
  105. package/docs/query-builder.md +465 -0
  106. package/docs/queue.md +549 -0
  107. package/docs/rate-limiting.md +253 -0
  108. package/docs/responses.md +336 -0
  109. package/docs/roles-and-2fa.md +418 -0
  110. package/docs/routing.md +1008 -0
  111. package/docs/scaffolding.md +335 -0
  112. package/docs/scheduler.md +533 -0
  113. package/docs/seeding.md +229 -0
  114. package/docs/session.md +451 -0
  115. package/docs/social.md +524 -0
  116. package/docs/storage.md +622 -0
  117. package/docs/structure.md +230 -0
  118. package/docs/support-policy.md +114 -0
  119. package/docs/telemetry.md +505 -0
  120. package/docs/tenancy.md +608 -0
  121. package/docs/testing/browser.md +153 -0
  122. package/docs/testing/console.md +130 -0
  123. package/docs/testing/database.md +238 -0
  124. package/docs/testing/flow-browser.md +216 -0
  125. package/docs/testing/http.md +441 -0
  126. package/docs/testing/index.md +240 -0
  127. package/docs/testing/mocking.md +410 -0
  128. package/docs/upgrade.md +192 -0
  129. package/docs/validator.md +549 -0
  130. package/docs/view.md +453 -0
  131. package/package.json +60 -0
  132. package/src/bin/mcp.ts +73 -0
  133. package/src/config.ts +63 -0
  134. package/src/errors.ts +27 -0
  135. package/src/index.ts +56 -0
  136. package/src/install/ArchInstallCommand.ts +189 -0
  137. package/src/install/detect.ts +98 -0
  138. package/src/install/guidelines.ts +290 -0
  139. package/src/install/markers.ts +77 -0
  140. package/src/install/mcpConfig.ts +81 -0
  141. package/src/mcp/index.ts +27 -0
  142. package/src/mcp/jsonrpc.ts +133 -0
  143. package/src/mcp/server.ts +307 -0
  144. package/src/mcp/stdio.ts +111 -0
  145. package/src/mcp/types.ts +146 -0
  146. package/src/probe/ArchProbeCommand.ts +48 -0
  147. package/src/probe/sentinel.ts +13 -0
  148. package/src/probe/topics.ts +291 -0
  149. package/src/provider/ArchProvider.ts +101 -0
  150. package/src/tools/_probe.ts +164 -0
  151. package/src/tools/apiSurface.ts +241 -0
  152. package/src/tools/appInfo.ts +88 -0
  153. package/src/tools/baselines.ts +210 -0
  154. package/src/tools/context.ts +37 -0
  155. package/src/tools/doctor.ts +93 -0
  156. package/src/tools/index.ts +50 -0
  157. package/src/tools/logs.ts +265 -0
  158. package/src/tools/routes.ts +133 -0
  159. package/src/tools/schema.ts +119 -0
  160. package/src/tools/searchDocs.ts +345 -0
@@ -0,0 +1,423 @@
1
+ ---
2
+ title: Helpers
3
+ description: Small, named, tree-shakeable functions for env, config, control flow, strings, and responses.
4
+ ---
5
+
6
+ # Helpers
7
+
8
+ `@zerotal/core` ships a set of small, focused helper functions for the things you
9
+ reach for constantly — reading environment variables, building responses,
10
+ massaging strings, and taming control flow. They are **named, tree-shakeable
11
+ exports**, never globals: import what you use.
12
+
13
+ ```typescript
14
+ // in a controller
15
+ import { env, config, tap, pipe, rescue, data_get, Str, collect } from "zerotal";
16
+ ```
17
+
18
+ ## Environment & paths
19
+
20
+ ### env
21
+
22
+ Read an environment variable with an optional, type-coerced fallback. This is the
23
+ canonical way to read env values — every config file uses it. The return type
24
+ follows the fallback's type.
25
+
26
+ ```typescript
27
+ // config/app.ts
28
+ env("APP_NAME", "Zerotal App"); // string
29
+ env("APP_DEBUG", false); // boolean — coerces 'true' / '1'
30
+ env("PORT", 3000); // number — coerces numeric strings
31
+ env("APP_KEY"); // string | undefined — no fallback
32
+ ```
33
+
34
+ ### requireEnv
35
+
36
+ Read a variable that must exist. Throws a `ConfigError` at boot if it's missing —
37
+ use it for secrets your app cannot run without.
38
+
39
+ ```typescript
40
+ // config/app.ts
41
+ const key = requireEnv("APP_KEY"); // throws ConfigError if unset
42
+ ```
43
+
44
+ ### basePath
45
+
46
+ Resolve a path relative to the project root (`process.cwd()`), regardless of which
47
+ file calls it. Use it when declaring route files so paths don't depend on the
48
+ caller's directory.
49
+
50
+ ```typescript
51
+ // bootstrap/app.ts
52
+ Application.create({ providers })
53
+ .routing({ web: basePath("routes/web.ts") })
54
+ .fileBasedRouting({ web: basePath("app/routes") });
55
+ ```
56
+
57
+ ### setAppEnv
58
+
59
+ Map a CLI command name to `APP_ENV` before the app is created. Called once in the
60
+ managed `zt.ts`; you rarely call it yourself. `serve`/`start`/`s` → `web`,
61
+ `worker`/`queue:work` → `worker`, anything else → `console`. A no-op if `APP_ENV`
62
+ is already a valid runtime mode.
63
+
64
+ ```typescript
65
+ // zt.ts
66
+ setAppEnv(process.argv[2]);
67
+ const { default: app } = await import("./bootstrap/app.ts");
68
+ ```
69
+
70
+ ## Configuration access
71
+
72
+ ### config
73
+
74
+ Read (and write) loaded configuration by dot-path, anywhere after boot.
75
+
76
+ ```typescript
77
+ // in a controller
78
+ config("app.name"); // string — typed from the registered config shape
79
+ config("app.port", 3000); // number — fallback must match the path's type
80
+ config.require("app.key"); // throws if absent
81
+ config.set("mail.driver", "log"); // override at runtime
82
+ config.all(); // the whole config map
83
+ config.safe("app.cors", {}); // returns the fallback if no app is booted
84
+ ```
85
+
86
+ Paths are type-aware: each resolves to the type declared by the owning package's
87
+ config shape, with autocomplete. Unknown paths fall back to `unknown`. See
88
+ [Configuration → Typed dot-paths](/docs/config-system#typed-dot-paths).
89
+
90
+ > **Tip** — `config.safe()` is the no-throw variant — handy in library code that
91
+ > may run before an application exists.
92
+
93
+ ### request
94
+
95
+ Reach the current request's `HttpContext` from anywhere in the async call chain —
96
+ no thread-through required. With a key, it reads a single merged input value (route
97
+ params, then parsed body, then query string).
98
+
99
+ ```typescript
100
+ // in a controller
101
+ request(); // the HttpContext
102
+ request("email"); // string | undefined — input named 'email'
103
+ request<number>("page", 1); // typed input with a fallback
104
+ ```
105
+
106
+ > **Warning** — `request()` throws if called outside an active HTTP request.
107
+ > Body resolution is synchronous: it only sees body data already parsed and cached
108
+ > (e.g. via a `FormRequest` or `await ctx.body()`).
109
+
110
+ ## Control flow
111
+
112
+ ### tap / tapAsync
113
+
114
+ Run a side effect on a value and return the value unchanged — perfect for emitting
115
+ an event or logging in the middle of a chain without breaking it.
116
+
117
+ ```typescript
118
+ // in a controller
119
+ return tap(await User.create(data), (user) => Events.emit(new UserRegistered(user.id)));
120
+
121
+ return await tapAsync(await User.create(data), async (user) => {
122
+ await Notification.send(user, new WelcomeEmail());
123
+ });
124
+ ```
125
+
126
+ ### pipe / pipeAsync
127
+
128
+ The sibling of `tap` — pass a value through a transformer and return the _result_.
129
+ Use `pipe` when the value should change, `tap` when it shouldn't.
130
+
131
+ ```typescript
132
+ // in a controller
133
+ const slug = pipe(post.title, (t) => t.toLowerCase().replace(/\s+/g, "-"));
134
+ const hashed = await pipeAsync(password, (p) => Hash.make(p));
135
+ ```
136
+
137
+ ### rescue / rescueSync
138
+
139
+ Run a callback and fall back to a value (or a function of the caught error) instead
140
+ of throwing. `rescue` awaits; `rescueSync` is for hot paths that can't await
141
+ (JSON parsing, attribute decoding).
142
+
143
+ ```typescript
144
+ // in a controller
145
+ const price = await rescue(() => stripe.getPrice(id), 0);
146
+ const user = await rescue(
147
+ () => User.findOrFail(id),
148
+ (e) => {
149
+ log(e);
150
+ return null;
151
+ },
152
+ );
153
+
154
+ const payload = rescueSync(() => JSON.parse(raw), {});
155
+ ```
156
+
157
+ ### data_get
158
+
159
+ Safely read a deeply nested value by dot-notation, returning a default when any
160
+ segment is absent. Built for untyped JSON — webhooks, third-party API responses —
161
+ where optional chaining gets unwieldy. Numeric segments index into arrays.
162
+
163
+ ```typescript
164
+ // in a webhook handler
165
+ data_get(payload, "user.address.city"); // 'Cape Town' or undefined
166
+ data_get(payload, "items.0.price", 0); // first item's price, or 0
167
+ ```
168
+
169
+ ## Strings — Str
170
+
171
+ `Str` is a namespace of pure string utilities. The common case-conversions are
172
+ also exported individually (`camelCase`, `snakeCase`).
173
+
174
+ ```typescript
175
+ // in a controller
176
+ Str.camelCase("user_id"); // 'userId'
177
+ Str.snakeCase("userId"); // 'user_id'
178
+ Str.pascalCase("user-id"); // 'UserId'
179
+ Str.kebab("UserId"); // 'user-id'
180
+ Str.slugify("Hello, World!"); // 'hello-world'
181
+ Str.titleCase("hello world"); // 'Hello World'
182
+ Str.capitalize("hello"); // 'Hello'
183
+ Str.lcfirst("Hello"); // 'hello'
184
+ Str.truncate(text, 50); // 'long text...' (custom suffix optional)
185
+ Str.words(text, 10); // first 10 words + suffix
186
+ Str.squish(" a b "); // 'a b'
187
+ Str.start(path, "/"); // ensure leading '/'
188
+ Str.finish(path, "/"); // ensure trailing '/'
189
+ Str.after(s, ":"); // substring after first ':'
190
+ Str.before(s, ":"); // substring before first ':'
191
+ Str.afterLast(s, "/"); // substring after last '/'
192
+ Str.beforeLast(s, "/"); // substring before last '/'
193
+ Str.contains(s, "x"); // boolean
194
+ Str.replaceFirst(s, a, b);
195
+ Str.replaceLast(s, a, b);
196
+ Str.padLeft(s, 5, "0"); // '00042'
197
+ Str.reverse(s);
198
+ Str.random(32); // random alphanumeric string
199
+ Str.isAlphanumeric(s); // boolean
200
+ ```
201
+
202
+ Extend it with your own helper via `Str.macro(name, fn)`.
203
+
204
+ ### Inflection & naming
205
+
206
+ These power the ORM's table-name convention and are exported directly:
207
+
208
+ ```typescript
209
+ // in a controller
210
+ import { pluralize, singularize, tableNameFor } from "zerotal";
211
+
212
+ pluralize("category"); // 'categories'
213
+ singularize("people"); // 'person'
214
+ tableNameFor("BlogPost"); // 'blog_posts'
215
+ ```
216
+
217
+ ## Objects — deepMerge
218
+
219
+ Recursively merge an override object onto a base, lodash-style: nested plain
220
+ objects merge key-by-key, while arrays, primitives, and class instances replace
221
+ wholesale. `undefined` values in the override are ignored. Neither argument is
222
+ mutated, and the result shares no mutable plain structure with either — every plain
223
+ object and array in the result is a fresh copy, so mutating a merged config can
224
+ never corrupt the module-level `defaults` it was built from. Prototype-polluting
225
+ keys (`__proto__`, `constructor`, `prototype`) are skipped, so it is safe to merge
226
+ untrusted input such as env files or parsed JSON. This is what makes the
227
+ `*Config({ ... })` factories preserve untouched defaults at every depth.
228
+
229
+ ```typescript
230
+ // in a config factory
231
+ import { deepMerge } from "zerotal";
232
+
233
+ deepMerge(
234
+ { smtp: { host: "localhost", port: 1025, secure: false } },
235
+ { smtp: { host: "mail.example.com" } },
236
+ );
237
+ // → { smtp: { host: 'mail.example.com', port: 1025, secure: false } }
238
+ ```
239
+
240
+ ### `DeepPartial<T>` — the shape an override may take
241
+
242
+ `deepMerge` accepts a `DeepPartial<T>`: every key optional, all the way down. A plain
243
+ `Partial<T>` only makes the _top_ level optional, which would make the commonest override
244
+ anyone writes a type error:
245
+
246
+ ```typescript
247
+ // in a config factory
248
+ import { deepMerge } from "zerotal";
249
+ import type { DeepPartial } from "zerotal";
250
+
251
+ interface MailConfigShape {
252
+ smtp: { host: string; port: number; secure: boolean };
253
+ }
254
+
255
+ // Overriding one field of a nested block, without restating the others.
256
+ const override: DeepPartial<MailConfigShape> = { smtp: { host: "mail.example.com" } };
257
+ ```
258
+
259
+ Arrays, `Date`s, `Map`s, `Set`s and functions are left whole rather than made partial,
260
+ matching the merge itself — those replace wholesale, so asking for a partial of one would
261
+ describe something `deepMerge` never does. An explicit `undefined` is allowed too, because
262
+ the merge documents it as _skipped_ rather than blanking a default.
263
+
264
+ Write your own config factory's parameter as `Partial<XConfigShape>` when the shape is
265
+ flat, and `DeepPartial<XConfigShape>` when it nests — both satisfy the package linter's
266
+ `config-partial` rule.
267
+
268
+ ### Arrays replace — they do not merge
269
+
270
+ An array in the override replaces the base array entirely. It is **never**
271
+ concatenated, de-duplicated, or merged element-by-element:
272
+
273
+ ```typescript
274
+ // in a config factory
275
+ deepMerge({ hosts: ["a", "b"] }, { hosts: ["c"] });
276
+ // → { hosts: ['c'] } (not ['a','b','c'], not ['c','b'])
277
+ ```
278
+
279
+ This is deliberate — there is no surprise-free universal rule for combining two
280
+ arrays. When you design a config or middleware option shape, pick the model that
281
+ matches how you want overrides to behave.
282
+
283
+ **Which model should I use?**
284
+
285
+ - **List the user should be able to extend** → expose a plain array and document
286
+ that setting it replaces the default. Have callers spread the default in
287
+ themselves: `SomeConfig({ hosts: [...DEFAULT_HOSTS, "extra"] })`.
288
+ - **Keyed, extensible sub-config** → model it as a nested **object** keyed by name
289
+ (like `cache.stores` or `storage.disks`) instead of an array. Objects merge, so a
290
+ user can add one entry without losing the built-ins.
291
+
292
+ > **Note** — The replacement array is deep-cloned, so mutating the merged result
293
+ > never reaches back into the value the caller passed in. Class instances (e.g. a
294
+ > configured `driver`) are replaced by reference — they keep their prototype and are
295
+ > never merged into.
296
+
297
+ ## Fluent wrappers
298
+
299
+ ### fluent
300
+
301
+ Wrap any value to chain `.pipe()` transforms and `.tap()` side effects, then unwrap
302
+ with `.get()`. Useful for readable builder-style code over a plain value.
303
+
304
+ ```typescript
305
+ // in a controller
306
+ const user = fluent(await User.find(id))
307
+ .tap((u) => log(`loaded ${u.email}`))
308
+ .get();
309
+ ```
310
+
311
+ ### collect
312
+
313
+ Wrap an array in a `Collection` for chainable, immutable transformations — `map`,
314
+ `filter`, `reduce`, `groupBy`, `pluck`, `sum`, `first`, `unique`, and more — a
315
+ fluent collection pipeline.
316
+
317
+ ```typescript
318
+ // in a controller
319
+ const topNames = collect(orders)
320
+ .filter((o) => o.paid)
321
+ .pluck("customerId")
322
+ .unique()
323
+ .toArray();
324
+ ```
325
+
326
+ > **Note** — `groupBy()` returns a plain `Record<string, T[]>`, not a `Collection`.
327
+ > Re-wrap a group with `collect(group)` if you need to keep chaining over it.
328
+
329
+ ## Responses
330
+
331
+ These build and send the HTTP response for the current request. The terminal
332
+ helpers (`json`, `view`, `html`, `markdown`, `file`) set `ctx.response` directly;
333
+ `redirect()` and `redirectTo()` return a chainable `ResponseBuilder`.
334
+
335
+ ```typescript
336
+ // in a controller
337
+ import { json, view, html, markdown, redirect, redirectTo, abort } from "zerotal";
338
+
339
+ json({ user }); // 200 application/json
340
+ json({ error: "Nope" }, 422); // custom status
341
+ html("<h1>Hi</h1>"); // 200 text/html
342
+ view(Welcome, { title: "Hi" }); // render a view component + props
343
+ markdown("# Title\n\nBody"); // render markdown → HTML
344
+
345
+ redirect("/dashboard"); // 302 by default
346
+ redirect("/login", 301); // custom status
347
+ redirect().back(); // back to the referrer
348
+ redirect().intended("/home"); // to the originally-requested URL
349
+ redirectTo("posts.show", { id }); // redirect to a named route
350
+ ```
351
+
352
+ `redirect()` and `redirect().back()` return a `ResponseBuilder` that lets you flash
353
+ data and messages onto the redirect:
354
+
355
+ ```typescript
356
+ // in a controller
357
+ return redirect("/posts").withSuccess("Post created.").with("highlight", post.id);
358
+
359
+ return redirect().back().withErrors({ title: "Title is required." });
360
+ ```
361
+
362
+ > **Tip** — Call `redirect()` with no arguments to pick the destination fluently:
363
+ > `redirect().to("posts.show", { id })`, `redirect().back()`, or
364
+ > `redirect().intended("/")`. The builder also exposes `withError`, `withWarning`,
365
+ > and `withInfo` alongside `withSuccess` and `withErrors`.
366
+
367
+ `abort()` throws a framework error that the exception handler renders:
368
+
369
+ ```typescript
370
+ // in a controller
371
+ abort("Something went wrong."); // → 500 with a message
372
+ abort(403, "You can't do that."); // status + message
373
+ abort(NotFoundError); // a ZerotalError subclass
374
+ ```
375
+
376
+ ## Dates — Carbon
377
+
378
+ Date and time get their own helper, `Carbon`, an immutable wrapper over the
379
+ `Temporal` API. It has its own page: [Carbon](/docs/carbon).
380
+
381
+ ```typescript
382
+ // in a controller
383
+ import { Carbon } from "zerotal/carbon";
384
+
385
+ Carbon.now().addDays(7).toDateString();
386
+ ```
387
+
388
+ ## References
389
+
390
+ | Helper | Signature | Description |
391
+ | ----------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------- |
392
+ | `env` | `env(key: string, fallback?: string \| boolean \| number)` | Read an env var, coerced to the fallback's type. |
393
+ | `requireEnv` | `requireEnv(key: string): string` | Read a required env var; throws `ConfigError` if unset. |
394
+ | `basePath` | `basePath(...segments: string[]): string` | Resolve a path from `process.cwd()`. |
395
+ | `setAppEnv` | `setAppEnv(command?: string): void` | Map a CLI command to `APP_ENV` before boot. |
396
+ | `config` | `config(path: string, fallback?): unknown` | Read config by dot-path (typed for known paths). |
397
+ | `config.set` | `config.set(path: string, value): void` | Override a config value at runtime. |
398
+ | `config.require` | `config.require(path: string): unknown` | Read config; throws when the path is absent. |
399
+ | `config.all` | `config.all(): Record<string, unknown>` | Return the whole config map. |
400
+ | `config.safe` | `config.safe(path: string, fallback): unknown` | Read config without throwing when no app is booted. |
401
+ | `request` | `request<T>(key?: string, fallback?: T): HttpContext \| T \| undefined` | Active `HttpContext`, or one merged input value. |
402
+ | `tap` / `tapAsync` | `tap<T>(value: T, cb: (v: T) => void): T` | Run a side effect, return the original value. |
403
+ | `pipe` / `pipeAsync` | `pipe<T, R>(value: T, fn: (v: T) => R): R` | Transform a value, return the result. |
404
+ | `rescue` / `rescueSync` | `rescue<T>(cb, fallback: T \| ((e) => T)): Promise<T>` | Run a callback, fall back instead of throwing. |
405
+ | `data_get` | `data_get(target, key: string, defaultValue?): unknown` | Read a nested value by dot-notation, with a default. |
406
+ | `deepMerge` | `deepMerge(base, override)` | Recursively merge objects; arrays/instances replace. |
407
+ | `fluent` | `fluent<T>(value: T): Fluent<T>` | Chainable `.pipe()` / `.tap()` / `.get()` wrapper. |
408
+ | `collect` | `collect<T>(items: T[]): Collection<T>` | Chainable, immutable array transformations. |
409
+ | `json` | `json(data: unknown, status = 200): void` | Send a JSON response. |
410
+ | `view` | `view(component, props?, status = 200): void` | Render a view component (or markup) as the response. |
411
+ | `html` | `html(markup, status = 200): void` | Send a raw HTML response. |
412
+ | `markdown` | `markdown(content, options?, status = 200): MarkdownBuilder` | Render markdown → HTML; chain `.withLayout()`. |
413
+ | `file` | `file(path, options?): Promise<void>` | Stream a file from disk; throws if missing. |
414
+ | `redirect` | `redirect(url?, status = 302): ResponseBuilder \| RedirectBuilder` | Redirect; no-arg form picks a destination fluently. |
415
+ | `redirectTo` | `redirectTo(name: string, params?, status = 302): ResponseBuilder` | Redirect to a named route. |
416
+ | `abort` | `abort(status \| message \| ErrorClass, message?): never` | Throw a framework HTTP error the handler renders. |
417
+
418
+ ## Next steps
419
+
420
+ - [Configuration](/docs/config-system) — where `env()` and `config()` get their values.
421
+ - [Responses](/docs/responses) — the response layer in depth.
422
+ - [Carbon](/docs/carbon) — the date-time helper.
423
+ - [HTTP Context](/docs/context) — what `request()` reaches for in the async tree.