@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.
- package/CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/api-surface.md +283 -0
- package/docs/about.md +676 -0
- package/docs/admin/actions.md +183 -0
- package/docs/admin/auth.md +89 -0
- package/docs/admin/dashboard.md +155 -0
- package/docs/admin/extending-ui.md +229 -0
- package/docs/admin/extending.md +205 -0
- package/docs/admin/forms.md +155 -0
- package/docs/admin/index.md +144 -0
- package/docs/admin/operations.md +224 -0
- package/docs/admin/references.md +174 -0
- package/docs/admin/resources.md +132 -0
- package/docs/admin/structure.md +158 -0
- package/docs/admin/tables.md +185 -0
- package/docs/admin/testing.md +138 -0
- package/docs/ai.md +373 -0
- package/docs/application.md +435 -0
- package/docs/arch.md +263 -0
- package/docs/assets.md +755 -0
- package/docs/audit.md +367 -0
- package/docs/authentication.md +1000 -0
- package/docs/authorization.md +529 -0
- package/docs/broadcasting/channels.md +170 -0
- package/docs/broadcasting/client.md +108 -0
- package/docs/broadcasting/events.md +190 -0
- package/docs/broadcasting/index.md +163 -0
- package/docs/broadcasting/references.md +84 -0
- package/docs/broadcasting/testing.md +132 -0
- package/docs/cache.md +387 -0
- package/docs/carbon.md +830 -0
- package/docs/changelog.md +465 -0
- package/docs/client/auth.md +113 -0
- package/docs/client/errors.md +139 -0
- package/docs/client/files.md +118 -0
- package/docs/client/index.md +128 -0
- package/docs/client/references.md +58 -0
- package/docs/client/requests.md +131 -0
- package/docs/client/resilience.md +141 -0
- package/docs/client/testing.md +146 -0
- package/docs/commands.md +450 -0
- package/docs/components.md +2427 -0
- package/docs/config-system.md +258 -0
- package/docs/container.md +596 -0
- package/docs/context.md +579 -0
- package/docs/contributing.md +164 -0
- package/docs/controllers.md +354 -0
- package/docs/conventions.md +466 -0
- package/docs/cookies.md +101 -0
- package/docs/csrf.md +206 -0
- package/docs/database.md +476 -0
- package/docs/deployment.md +434 -0
- package/docs/devtools.md +1013 -0
- package/docs/email-verification.md +320 -0
- package/docs/encryption.md +380 -0
- package/docs/errors.md +317 -0
- package/docs/events.md +420 -0
- package/docs/flow/components.md +846 -0
- package/docs/flow/decorators.md +458 -0
- package/docs/flow/events.md +420 -0
- package/docs/flow/forms.md +551 -0
- package/docs/flow/index.md +568 -0
- package/docs/flow/layouts.md +793 -0
- package/docs/flow/lifecycle.md +336 -0
- package/docs/flow/pagination.md +402 -0
- package/docs/flow/performance.md +262 -0
- package/docs/flow/references.md +317 -0
- package/docs/flow/routing.md +550 -0
- package/docs/flow/testing.md +447 -0
- package/docs/getting-started.md +286 -0
- package/docs/health.md +269 -0
- package/docs/helpers.md +423 -0
- package/docs/i18n.md +414 -0
- package/docs/index.md +65 -0
- package/docs/inertia/build.md +95 -0
- package/docs/inertia/devtools.md +197 -0
- package/docs/inertia/index.md +267 -0
- package/docs/inertia/middleware.md +81 -0
- package/docs/inertia/props.md +507 -0
- package/docs/inertia/references.md +144 -0
- package/docs/inertia/rendering.md +189 -0
- package/docs/inertia/ssr.md +102 -0
- package/docs/inspirations.md +257 -0
- package/docs/lifecycle.md +331 -0
- package/docs/lock.md +454 -0
- package/docs/logger.md +517 -0
- package/docs/media.md +582 -0
- package/docs/middleware.md +509 -0
- package/docs/migrations.md +529 -0
- package/docs/monitor.md +377 -0
- package/docs/notifications.md +848 -0
- package/docs/orm/casts.md +365 -0
- package/docs/orm/factories.md +231 -0
- package/docs/orm/index.md +663 -0
- package/docs/orm/lifecycle.md +421 -0
- package/docs/orm/queries.md +692 -0
- package/docs/orm/relationships.md +440 -0
- package/docs/orm/serialization.md +251 -0
- package/docs/package-development.md +536 -0
- package/docs/pagination.md +340 -0
- package/docs/password-reset.md +335 -0
- package/docs/providers.md +447 -0
- package/docs/query-builder.md +465 -0
- package/docs/queue.md +549 -0
- package/docs/rate-limiting.md +253 -0
- package/docs/responses.md +336 -0
- package/docs/roles-and-2fa.md +418 -0
- package/docs/routing.md +1008 -0
- package/docs/scaffolding.md +335 -0
- package/docs/scheduler.md +533 -0
- package/docs/seeding.md +229 -0
- package/docs/session.md +451 -0
- package/docs/social.md +524 -0
- package/docs/storage.md +622 -0
- package/docs/structure.md +230 -0
- package/docs/support-policy.md +114 -0
- package/docs/telemetry.md +505 -0
- package/docs/tenancy.md +608 -0
- package/docs/testing/browser.md +153 -0
- package/docs/testing/console.md +130 -0
- package/docs/testing/database.md +238 -0
- package/docs/testing/flow-browser.md +216 -0
- package/docs/testing/http.md +441 -0
- package/docs/testing/index.md +240 -0
- package/docs/testing/mocking.md +410 -0
- package/docs/upgrade.md +192 -0
- package/docs/validator.md +549 -0
- package/docs/view.md +453 -0
- package/package.json +60 -0
- package/src/bin/mcp.ts +73 -0
- package/src/config.ts +63 -0
- package/src/errors.ts +27 -0
- package/src/index.ts +56 -0
- package/src/install/ArchInstallCommand.ts +189 -0
- package/src/install/detect.ts +98 -0
- package/src/install/guidelines.ts +290 -0
- package/src/install/markers.ts +77 -0
- package/src/install/mcpConfig.ts +81 -0
- package/src/mcp/index.ts +27 -0
- package/src/mcp/jsonrpc.ts +133 -0
- package/src/mcp/server.ts +307 -0
- package/src/mcp/stdio.ts +111 -0
- package/src/mcp/types.ts +146 -0
- package/src/probe/ArchProbeCommand.ts +48 -0
- package/src/probe/sentinel.ts +13 -0
- package/src/probe/topics.ts +291 -0
- package/src/provider/ArchProvider.ts +101 -0
- package/src/tools/_probe.ts +164 -0
- package/src/tools/apiSurface.ts +241 -0
- package/src/tools/appInfo.ts +88 -0
- package/src/tools/baselines.ts +210 -0
- package/src/tools/context.ts +37 -0
- package/src/tools/doctor.ts +93 -0
- package/src/tools/index.ts +50 -0
- package/src/tools/logs.ts +265 -0
- package/src/tools/routes.ts +133 -0
- package/src/tools/schema.ts +119 -0
- package/src/tools/searchDocs.ts +345 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Configuration
|
|
3
|
+
description: Read deployment state, structure it in typed config files, and access it anywhere at runtime.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Configuration
|
|
7
|
+
|
|
8
|
+
Zerotal separates three things: deployment state (`env()`), code-level structure (`config/*.ts`), and runtime access (`config()`). You only need all three when your config has genuine structure or conditional logic — simple apps can rely on `env()` alone.
|
|
9
|
+
|
|
10
|
+
## Mental model
|
|
11
|
+
|
|
12
|
+
Think of configuration as a pipeline from the environment to your code:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
.env / process env config/*.ts files anywhere in the app
|
|
16
|
+
────────────────── ───────────────── ───────────────────
|
|
17
|
+
env("PORT") ─────► AppConfig({ ... }) ─────► config("app.port")
|
|
18
|
+
(raw strings) (typed structure) (typed dot-path read)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- `env()` pulls a single value out of the environment, coercing it to the type of your fallback.
|
|
22
|
+
- A `config/<name>.ts` file assembles those values into a typed object via a package helper (`AppConfig`, `DatabaseConfig`, …).
|
|
23
|
+
- At boot, every `config/*.ts` file is loaded into the config store; `config()` reads from it by dot-path.
|
|
24
|
+
|
|
25
|
+
> **Tip** — Reach for the next layer only when you need it. A value used in exactly one place can stay an `env()` call; promote it to a config file when it gains structure, defaults, or conditional logic.
|
|
26
|
+
|
|
27
|
+
## The env helper
|
|
28
|
+
|
|
29
|
+
Read environment variables with optional type coercion and a fallback. The fallback's type decides how the raw string is coerced:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// config/app.ts (or anywhere)
|
|
33
|
+
import { env } from "zerotal";
|
|
34
|
+
|
|
35
|
+
const port = env("PORT", 3000); // number fallback → coerced to number
|
|
36
|
+
const debug = env("APP_DEBUG", false); // boolean fallback → "true"/"1" become true
|
|
37
|
+
const appName = env("APP_NAME", "Zerotal App"); // string fallback
|
|
38
|
+
const apiKey = env("API_KEY"); // no fallback → string | undefined
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`env()` reads `Bun.env` at call time. Use it in config files, providers, and anywhere you need deployment-time values.
|
|
42
|
+
|
|
43
|
+
> **Note** — When you need a value to be present, use `requireEnv("APP_KEY")` instead — it throws a `ConfigError` at boot if the variable is unset, rather than returning `undefined`.
|
|
44
|
+
|
|
45
|
+
## Config files
|
|
46
|
+
|
|
47
|
+
Config files live in `config/`. Each file exports a typed object via a package helper:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// config/database.ts
|
|
51
|
+
import { DatabaseConfig } from "@zerotal/orm";
|
|
52
|
+
import { env } from "zerotal";
|
|
53
|
+
|
|
54
|
+
export default DatabaseConfig({
|
|
55
|
+
url: env("DATABASE_URL", "sqlite://./database.sqlite"),
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// config/session.ts
|
|
61
|
+
import { SessionConfig } from "@zerotal/session";
|
|
62
|
+
import { env } from "zerotal";
|
|
63
|
+
|
|
64
|
+
export default SessionConfig({
|
|
65
|
+
driver: env("SESSION_DRIVER", "cookie") as "cookie" | "redis",
|
|
66
|
+
secret: env("SESSION_SECRET", ""),
|
|
67
|
+
lifetime: 86400,
|
|
68
|
+
secure: env("APP_ENV") === "production",
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Config helpers (`DatabaseConfig`, `SessionConfig`, etc.) are typed factory functions that give you autocomplete and catch typos. Some — like `AppConfig` — also fill in defaults for fields you omit.
|
|
73
|
+
|
|
74
|
+
## The config helper
|
|
75
|
+
|
|
76
|
+
Access any loaded config value at runtime:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// in a provider, middleware, or controller
|
|
80
|
+
import { config } from "zerotal";
|
|
81
|
+
|
|
82
|
+
config("app.name"); // get — typed as string (see below)
|
|
83
|
+
config("app.name", "Zerotal"); // get with fallback — fallback must match the path's type
|
|
84
|
+
config.require("app.key"); // throws ConfigError if absent
|
|
85
|
+
config.set("app.debug", true); // override at runtime (useful in tests)
|
|
86
|
+
config.all(); // dump all loaded config as a flat record
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Dot-notation maps to the config file path and the key within it. `config('database.url')` reads `url` from `config/database.ts`.
|
|
90
|
+
|
|
91
|
+
> **Note** — `config()` resolves against the booted application's config store. When no app is booted (some test or script contexts), use `config.safe("app.name", "fallback")`, which returns the fallback instead of throwing.
|
|
92
|
+
|
|
93
|
+
### Typed dot-paths
|
|
94
|
+
|
|
95
|
+
`config()` is type-aware. Each path resolves to the type declared in the owning package's `*ConfigShape`, with autocomplete on the path string:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// in application code
|
|
99
|
+
config("app.name"); // string
|
|
100
|
+
config("app.port"); // number
|
|
101
|
+
config("cache.ttl"); // number
|
|
102
|
+
config("app.throttle.maxAttempts"); // number — nested paths work too
|
|
103
|
+
config.set("app.debug", "yes"); // type error: expected boolean
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
This works exactly like the container's `ContainerBindings`: there's a `ConfigRegistry` interface that every config-owning package augments by namespace. Core registers `app` and `health`; each package registers its own next to its `*ConfigShape`:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// in a package's config registry declaration
|
|
110
|
+
declare module "zerotal" {
|
|
111
|
+
interface ConfigRegistry {
|
|
112
|
+
cache: CacheConfigShape;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
A namespace lights up as typed once its package is imported (which an app does by referencing its `XConfig` factory in `config/<namespace>.ts`). Paths outside any registered namespace still compile — they fall back to the untyped `config(path: string)` overload returning `unknown`, so dynamic access is never blocked.
|
|
118
|
+
|
|
119
|
+
## Which layer do I use?
|
|
120
|
+
|
|
121
|
+
| Layer | What it does | Reach for it when |
|
|
122
|
+
| ------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
123
|
+
| `env()` | Reads deployment state (env vars) | Credentials, URLs, driver names — anything that changes per environment |
|
|
124
|
+
| `config/*.ts` | Assembles code-level structure and logic | Multi-field configs, conditional logic, code references (class constructors, strategy objects) |
|
|
125
|
+
| `config()` | Runtime access to loaded config | In service providers, middleware, and application code that needs cross-cutting config values |
|
|
126
|
+
|
|
127
|
+
The rule of thumb: read raw values with `env()`, shape and default them in a `config/*.ts` file, and read the shaped result anywhere with `config()`.
|
|
128
|
+
|
|
129
|
+
## How config loads at boot
|
|
130
|
+
|
|
131
|
+
Zerotal loads config **eagerly** when the application boots, before any provider registers:
|
|
132
|
+
|
|
133
|
+
- During `boot()`, the app auto-discovers and imports every `config/*.ts` file, taking each file's `default` export.
|
|
134
|
+
- Those exports are merged into the `ConfigManager` (bound in the container under the `"config"` key) before the provider `onRegister` → `onBooting` → `onBooted` phases run.
|
|
135
|
+
- A file that throws on import (for example, a missing required env var) is skipped during auto-discovery rather than crashing the whole boot.
|
|
136
|
+
|
|
137
|
+
Because every file is loaded as a normal module, a config file may `import` and read other modules at the top level — just avoid circular config imports between files.
|
|
138
|
+
|
|
139
|
+
> **Warning** — Auto-discovery silently skips a config file that throws while importing. If a namespace seems to be missing all its values, check that the file imports cleanly and that its required env vars are set.
|
|
140
|
+
|
|
141
|
+
## Overriding config in tests
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// in a test setup file
|
|
145
|
+
import { config } from "zerotal";
|
|
146
|
+
|
|
147
|
+
beforeEach(() => {
|
|
148
|
+
config.set("mail.driver", "log"); // force log driver in tests
|
|
149
|
+
config.set("queue.driver", "sync");
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
> **Note** — `config.set()` overrides in-memory only. `.env` is never modified.
|
|
154
|
+
|
|
155
|
+
## Application-level config
|
|
156
|
+
|
|
157
|
+
Create `config/app.ts` for app-wide settings:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// config/app.ts
|
|
161
|
+
import { env } from "zerotal";
|
|
162
|
+
import { AppConfig } from "zerotal/config";
|
|
163
|
+
|
|
164
|
+
export default AppConfig({
|
|
165
|
+
name: "Example",
|
|
166
|
+
url: env("APP_URL", "http://localhost:3000"),
|
|
167
|
+
key: env("APP_KEY", "changeme-in-production"),
|
|
168
|
+
|
|
169
|
+
cors: {
|
|
170
|
+
origin: env("CORS_ORIGIN", "*"),
|
|
171
|
+
credentials: false,
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
throttle: {
|
|
175
|
+
maxAttempts: 120,
|
|
176
|
+
windowSeconds: 60,
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
secureHeaders: {
|
|
180
|
+
frameOptions: "SAMEORIGIN",
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`AppConfig()` fills in sensible defaults for everything you omit (`env`, `key`, `debug`, `url`, `port`, `locale`, `timezone`, `http3`, `health`, `cors`, `throttle`, `secureHeaders`, and the `conventions` auto-discovery settings). Read any value with `config('app.name')`, `config('app.cors.origin')`, etc. The auto-discovery settings live under the `conventions` key — see [Conventions](/docs/conventions).
|
|
186
|
+
|
|
187
|
+
## Loading config explicitly
|
|
188
|
+
|
|
189
|
+
The CLI entry (`zt.ts`) can load config **synchronously** at the top level and inject it into the app, so it's available before anything boots:
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// zt.ts
|
|
193
|
+
import { Application } from "zerotal";
|
|
194
|
+
import { configLoader } from "zerotal/config";
|
|
195
|
+
|
|
196
|
+
const config = configLoader("./config"); // sync — scans config/*.ts, safe at top level
|
|
197
|
+
config.validate(); // runs each file's optional validate() export
|
|
198
|
+
|
|
199
|
+
const app = Application.create({ config }); // …or app.useConfig(config)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`configLoader(dir)` returns a `ConfigLoader` with `all()`, `get("dot.path", fallback)`, `has(path)`, and `validate()`. A config file may export a named `validate(config)` function; `ConfigLoader.validate()` runs them all and throws on the first failure.
|
|
203
|
+
|
|
204
|
+
**One source of truth.** If config was passed to `Application.create({ config })`, a later `useConfig(...)` is **ignored** (create wins) — so the framework-managed `zt.ts`, which always calls `useConfig(...)`, never conflicts with an app that prefers to pass config to `create()`. When neither is used, the app auto-discovers `config/*.ts` at boot as described above.
|
|
205
|
+
|
|
206
|
+
## Environment files
|
|
207
|
+
|
|
208
|
+
Zerotal automatically loads `.env` in development. For production, set variables in your deployment platform.
|
|
209
|
+
|
|
210
|
+
> **Danger** — Never commit `.env` to version control. It holds real secrets. Commit `.env.example` with safe defaults instead.
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
# .env.example (committed — safe defaults, no secrets)
|
|
214
|
+
APP_NAME=My App
|
|
215
|
+
APP_ENV=local
|
|
216
|
+
APP_KEY=
|
|
217
|
+
DATABASE_URL=sqlite://./database.sqlite
|
|
218
|
+
SESSION_SECRET=
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# .env (gitignored — real values)
|
|
223
|
+
APP_KEY=base64:abcdef...
|
|
224
|
+
DATABASE_URL=mysql://user:pass@localhost:3306/mydb
|
|
225
|
+
SESSION_SECRET=super-secret
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Use `APP_ENV` to differentiate behaviour:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// in application code
|
|
232
|
+
if (config("app.env") === "production") {
|
|
233
|
+
// production-only logic
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## References
|
|
238
|
+
|
|
239
|
+
| Member | Signature | Description |
|
|
240
|
+
| ----------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
241
|
+
| `env` | `env(key: string, fallback?: string \| boolean \| number)` | Read an env var, coercing to the fallback's type; `string \| undefined` with no fallback. |
|
|
242
|
+
| `requireEnv` | `requireEnv(key: string): string` | Read a required env var; throws `ConfigError` if unset. |
|
|
243
|
+
| `config` | `config(path: string, fallback?): value` | Read a config value by dot-path, optionally with a fallback. |
|
|
244
|
+
| `config.require` | `config.require(path: string): value` | Read a config value; throws `ConfigError` if absent or null. |
|
|
245
|
+
| `config.set` | `config.set(path: string, value): void` | Set a config value at runtime (in-memory only). |
|
|
246
|
+
| `config.all` | `config.all(): Record<string, unknown>` | Return all loaded config as a record. |
|
|
247
|
+
| `config.safe` | `config.safe(path: string, fallback): value` | Read without throwing when no app is booted; returns the fallback. |
|
|
248
|
+
| `AppConfig` | `AppConfig(options): AppConfigShape` | Build the `app` namespace config, filling defaults for omitted fields. |
|
|
249
|
+
| `configLoader` | `configLoader(dir = "./config"): ConfigLoader` | Synchronously load a `config/` directory into a `ConfigLoader`. |
|
|
250
|
+
| `ConfigLoader.get` | `get(key: string, fallback?): value` | Dot-path read against the loaded map. |
|
|
251
|
+
| `ConfigLoader.validate` | `validate(): this` | Run each file's optional `validate(config)` export, throwing on failure. |
|
|
252
|
+
|
|
253
|
+
## Next steps
|
|
254
|
+
|
|
255
|
+
- [Conventions](/docs/conventions) — the auto-discovery settings under the `conventions` key.
|
|
256
|
+
- [Providers](/docs/providers) — where `config()` is most often read.
|
|
257
|
+
- [Application](/docs/application) — how config is injected and loaded at boot.
|
|
258
|
+
- [Deployment](/docs/deployment) — setting env vars in production.
|