@spfn/core 0.3.0-beta.3 → 0.3.0-beta.30
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/README.md +301 -10
- package/dist/app-config/index.d.ts +39 -1
- package/dist/app-config/index.js.map +1 -1
- package/dist/authz/index.js +47 -391
- package/dist/authz/index.js.map +1 -1
- package/dist/{boss-D16fO2oG.d.ts → boss-BiDCbbAQ.d.ts} +60 -7
- package/dist/codegen/index.d.ts +157 -16
- package/dist/codegen/index.js +772 -166
- package/dist/codegen/index.js.map +1 -1
- package/dist/config/index.js +4 -4
- package/dist/config/index.js.map +1 -1
- package/dist/contract/index.d.ts +39 -16
- package/dist/contract/index.js +147 -23
- package/dist/contract/index.js.map +1 -1
- package/dist/db/index.d.ts +230 -35
- package/dist/db/index.js +316 -160
- package/dist/db/index.js.map +1 -1
- package/dist/env/index.d.ts +6 -442
- package/dist/env/index.js +13 -16
- package/dist/env/index.js.map +1 -1
- package/dist/env/loader.js +24 -1
- package/dist/env/loader.js.map +1 -1
- package/dist/error-CIZlYJlL.d.ts +157 -0
- package/dist/errors/index.d.ts +18 -1
- package/dist/errors/index.js +47 -391
- package/dist/errors/index.js.map +1 -1
- package/dist/event/index.d.ts +5 -5
- package/dist/event/index.js +202 -3
- package/dist/event/index.js.map +1 -1
- package/dist/event/sse/client.d.ts +18 -4
- package/dist/event/sse/client.js +94 -18
- package/dist/event/sse/client.js.map +1 -1
- package/dist/event/sse/index.d.ts +18 -5
- package/dist/event/sse/index.js +452 -114
- package/dist/event/sse/index.js.map +1 -1
- package/dist/event/ws/client.d.ts +3 -2
- package/dist/event/ws/index.d.ts +4 -3
- package/dist/job/index.d.ts +48 -3
- package/dist/job/index.js +131 -52
- package/dist/job/index.js.map +1 -1
- package/dist/logger/index.js +0 -12
- package/dist/logger/index.js.map +1 -1
- package/dist/middleware/index.js +52 -397
- package/dist/middleware/index.js.map +1 -1
- package/dist/nextjs/index.d.ts +75 -14
- package/dist/nextjs/index.js +200 -84
- package/dist/nextjs/index.js.map +1 -1
- package/dist/nextjs/server.d.ts +46 -8
- package/dist/nextjs/server.js +15 -1
- package/dist/nextjs/server.js.map +1 -1
- package/dist/ops/index.d.ts +61 -42
- package/dist/ops/index.js +648 -97
- package/dist/ops/index.js.map +1 -1
- package/dist/registry-C2KQCh0m.d.ts +473 -0
- package/dist/route/index.d.ts +5 -2
- package/dist/route/index.js +107 -28
- package/dist/route/index.js.map +1 -1
- package/dist/route/types.d.ts +7 -1
- package/dist/{router-Cy7rAfmj.d.ts → route-builder-DRW-MSCJ.d.ts} +51 -126
- package/dist/router-C57y-vz1.d.ts +184 -0
- package/dist/router-CX5uVjmU.d.ts +406 -0
- package/dist/server/index.d.ts +130 -7
- package/dist/server/index.js +1174 -164
- package/dist/server/index.js.map +1 -1
- package/dist/state/client.d.ts +206 -0
- package/dist/state/client.js +678 -0
- package/dist/state/client.js.map +1 -0
- package/dist/state/index.d.ts +443 -0
- package/dist/state/index.js +644 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/react.d.ts +49 -0
- package/dist/state/react.js +50 -0
- package/dist/state/react.js.map +1 -0
- package/dist/surface/index.d.ts +115 -0
- package/dist/surface/index.js +1013 -0
- package/dist/surface/index.js.map +1 -0
- package/dist/token-manager-Ckjt2-qq.d.ts +122 -0
- package/dist/{types-CfYVhIQ9.d.ts → types-5Rl11_Nb.d.ts} +43 -4
- package/dist/types-CKH0D3Dy.d.ts +441 -0
- package/dist/{types-ZQODsBft.d.ts → types-CurMab2Q.d.ts} +52 -2
- package/dist/{types-2AbaW4Ie.d.ts → types-DncqXfWN.d.ts} +4 -3
- package/docs/file-upload.md +195 -333
- package/package.json +39 -9
- package/src/cache/README.md +330 -0
- package/src/codegen/README.md +721 -0
- package/src/config/README.md +333 -0
- package/src/contract/README.md +442 -0
- package/src/db/README.md +589 -0
- package/src/db/manager/README.md +500 -0
- package/src/db/schema/README.md +354 -0
- package/src/db/transaction/README.md +845 -0
- package/src/env/README.md +787 -0
- package/src/errors/README.md +445 -0
- package/src/event/README.md +994 -0
- package/src/job/README.md +613 -0
- package/src/logger/README.md +321 -0
- package/src/middleware/README.md +634 -0
- package/src/nextjs/README.md +756 -0
- package/src/route/README.md +763 -0
- package/src/security/README.md +100 -0
- package/src/server/README.md +704 -0
- package/src/state/README.md +806 -0
- package/dist/token-manager-BT5EnUAR.d.ts +0 -278
- package/dist/types-9oszaJqp.d.ts +0 -250
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# @spfn/core/config — @spfn/core's own validated env config
|
|
2
|
+
|
|
3
|
+
A **prebuilt env registry** for the variables `@spfn/core` itself consumes (database,
|
|
4
|
+
cache, server, fetch, Next.js integration). It is a thin application of `@spfn/core/env`:
|
|
5
|
+
it owns one fixed schema (`coreEnvSchema`), builds a registry from it, and exports the
|
|
6
|
+
validated proxy. It does **not** add new env machinery — for the schema DSL, parsers,
|
|
7
|
+
registry semantics, and file loading, see [@spfn/core/env](../env/README.md).
|
|
8
|
+
|
|
9
|
+
## Import paths
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// The validated proxy + the schema + the registry — all from one entry point.
|
|
13
|
+
import { env, envSchema, registry } from '@spfn/core/config';
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
There is a single entry point (`@spfn/core/config`). It re-exports nothing from
|
|
17
|
+
`@spfn/core/env`; if you need `defineEnvSchema`, parsers, `loadEnv`, type guards, etc.,
|
|
18
|
+
import them from `@spfn/core/env` / `@spfn/core/env/loader` directly.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Public API (complete)
|
|
23
|
+
|
|
24
|
+
The module exports exactly three values:
|
|
25
|
+
|
|
26
|
+
| Export | Type | What it is |
|
|
27
|
+
|--------|------|------------|
|
|
28
|
+
| `env` | `InferEnvType<typeof coreEnvSchema>` (a **Proxy**) | The validated config object. Read variables off it. |
|
|
29
|
+
| `envSchema` | `EnvSchemaCollection` | The schema object (`coreEnvSchema`), re-exported under the name `envSchema`. Read `.description` / `.default` / `.examples` per key. |
|
|
30
|
+
| `registry` | `EnvRegistry` | The `EnvRegistry` instance backing `env` (`createEnvRegistry(coreEnvSchema)`). Exposes `.validate()`, `.validateAll()`, `.reset()`, `.register(...)`. |
|
|
31
|
+
|
|
32
|
+
`env` is literally `registry.validate()` — they are the same proxy.
|
|
33
|
+
|
|
34
|
+
> **No** `getEnv` / `loadConfig` / `config()` / `getConfig` function exists, and the schema
|
|
35
|
+
> is **not** something you pass in — it is fixed. To define your *own* app's variables,
|
|
36
|
+
> build a separate schema/registry with `@spfn/core/env`; do not try to extend
|
|
37
|
+
> `coreEnvSchema` by mutation.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { env } from '@spfn/core/config';
|
|
45
|
+
|
|
46
|
+
const poolMax: number = env.DB_POOL_MAX; // number (default 10)
|
|
47
|
+
const logLevel = env.SPFN_LOG_LEVEL; // 'debug' | 'info' | 'warn' | 'error' | 'fatal'
|
|
48
|
+
const apiUrl: string = env.SPFN_API_URL; // string (required)
|
|
49
|
+
const appUrl = env.SPFN_APP_URL; // string | undefined (optional)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
In the **SPFN server** entry point, call `loadEnv()` (from `@spfn/core/env/loader`)
|
|
53
|
+
**before** reading any value, so `process.env` is populated from the `.env*` files:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { loadEnv } from '@spfn/core/env/loader';
|
|
57
|
+
import { env } from '@spfn/core/config';
|
|
58
|
+
|
|
59
|
+
loadEnv(); // populate process.env (server reads .env.server too)
|
|
60
|
+
console.log(env.PORT); // validated lazily, here
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
In **Next.js** code, do **not** call `loadEnv()` — Next.js loads `.env*` itself. Just read
|
|
64
|
+
from `env`.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Validation is lazy (read this before relying on startup checks)
|
|
69
|
+
|
|
70
|
+
`env` is the Proxy returned by `registry.validate()`. Importing `@spfn/core/config` does
|
|
71
|
+
**not** read or validate any variable value. Each variable is read from `process.env`,
|
|
72
|
+
defaulted, and run through its `validator` **at the moment you access the property**.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { env } from '@spfn/core/config'; // imports the proxy — validates nothing yet
|
|
76
|
+
import { loadEnv } from '@spfn/core/env/loader';
|
|
77
|
+
|
|
78
|
+
loadEnv();
|
|
79
|
+
env.SPFN_API_URL; // read + validated HERE; throws if missing (required) or invalid
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Consequences:
|
|
83
|
+
|
|
84
|
+
- A missing **required** variable (`SPFN_API_URL`) does not
|
|
85
|
+
throw on import — it throws on first access (`Error('Environment validation failed')`).
|
|
86
|
+
- You may import `env` before `loadEnv()` runs; values are picked up lazily.
|
|
87
|
+
- For an **eager** all-at-once check (CI / startup gate), call `registry.validateAll()`
|
|
88
|
+
(returns `{ errors, warnings }`) or pass `registry` to `validateAllEnv([...])` from
|
|
89
|
+
`@spfn/core/env`. `SKIP_ENV_VALIDATION=true` skips only the lazy `required` check, not
|
|
90
|
+
these eager checks.
|
|
91
|
+
- **The SPFN server runs that eager check at boot.** `startServer` validates this
|
|
92
|
+
registry — plus any registries the app hands over with
|
|
93
|
+
`defineServerConfig().env({ registries })` — before it listens, and exits with code 1
|
|
94
|
+
listing each failing key (never a value). See
|
|
95
|
+
[Boot-time check](../env/README.md#boot-time-check-the-server).
|
|
96
|
+
|
|
97
|
+
See [@spfn/core/env](../env/README.md) for the full registry / proxy / `SKIP_ENV_VALIDATION`
|
|
98
|
+
semantics — this module inherits all of it unchanged.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Reading schema metadata
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { envSchema } from '@spfn/core/config';
|
|
106
|
+
|
|
107
|
+
envSchema.DB_POOL_MAX.description; // 'Maximum number of database connections in pool'
|
|
108
|
+
envSchema.DB_POOL_MAX.default; // 10
|
|
109
|
+
envSchema.DB_POOL_MAX.examples; // [10, 20, 50]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`envSchema` is the schema object, not the values. Use `env` for actual (validated) values.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Environment variables (the fixed `coreEnvSchema`)
|
|
117
|
+
|
|
118
|
+
All variables below are exactly what `coreEnvSchema` declares. URL variables marked with a
|
|
119
|
+
validator **throw on access** if the value is present but malformed.
|
|
120
|
+
|
|
121
|
+
### Core
|
|
122
|
+
|
|
123
|
+
| Variable | Type | Default | Notes |
|
|
124
|
+
|----------|------|---------|-------|
|
|
125
|
+
| `NODE_ENV` | `'local' \| 'development' \| 'staging' \| 'production' \| 'test'` | `'local'` | `nextjs: true` |
|
|
126
|
+
|
|
127
|
+
### Database — connection URLs (all optional, all `sensitive`, validated as postgres URLs)
|
|
128
|
+
|
|
129
|
+
| Variable | Type | Required | Validator |
|
|
130
|
+
|----------|------|----------|-----------|
|
|
131
|
+
| `DATABASE_URL` | `string` | No | `parsePostgresUrl` |
|
|
132
|
+
| `DATABASE_WRITE_URL` | `string` | No | `parsePostgresUrl` |
|
|
133
|
+
| `DATABASE_READ_URL` | `string` | No | `parsePostgresUrl` |
|
|
134
|
+
|
|
135
|
+
### Database — connection pool
|
|
136
|
+
|
|
137
|
+
| Variable | Type | Default |
|
|
138
|
+
|----------|------|---------|
|
|
139
|
+
| `DB_POOL_MAX` | `number` | `10` |
|
|
140
|
+
| `DB_POOL_IDLE_TIMEOUT` | `number` | `30` (seconds) |
|
|
141
|
+
|
|
142
|
+
### Database — retry
|
|
143
|
+
|
|
144
|
+
| Variable | Type | Default |
|
|
145
|
+
|----------|------|---------|
|
|
146
|
+
| `DB_RETRY_MAX` | `number` | `3` |
|
|
147
|
+
| `DB_RETRY_INITIAL_DELAY` | `number` | `100` (ms) |
|
|
148
|
+
| `DB_RETRY_MAX_DELAY` | `number` | `10000` (ms) |
|
|
149
|
+
| `DB_RETRY_FACTOR` | `number` | `2` |
|
|
150
|
+
|
|
151
|
+
### Database — health check
|
|
152
|
+
|
|
153
|
+
| Variable | Type | Default |
|
|
154
|
+
|----------|------|---------|
|
|
155
|
+
| `DB_HEALTH_CHECK_ENABLED` | `boolean` | `true` |
|
|
156
|
+
| `DB_HEALTH_CHECK_INTERVAL` | `number` | `60000` (ms) |
|
|
157
|
+
| `DB_HEALTH_CHECK_RECONNECT` | `boolean` | `true` |
|
|
158
|
+
| `DB_HEALTH_CHECK_MAX_RETRIES` | `number` | `3` |
|
|
159
|
+
| `DB_HEALTH_CHECK_RETRY_INTERVAL` | `number` | `5000` (ms) |
|
|
160
|
+
|
|
161
|
+
### Database — monitoring
|
|
162
|
+
|
|
163
|
+
| Variable | Type | Default |
|
|
164
|
+
|----------|------|---------|
|
|
165
|
+
| `DB_MONITORING_ENABLED` | `boolean` | `false` |
|
|
166
|
+
| `DB_MONITORING_SLOW_THRESHOLD` | `number` | `1000` (ms) |
|
|
167
|
+
| `DB_MONITORING_LOG_QUERIES` | `boolean` | `false` |
|
|
168
|
+
|
|
169
|
+
### Database — transaction / development
|
|
170
|
+
|
|
171
|
+
| Variable | Type | Default |
|
|
172
|
+
|----------|------|---------|
|
|
173
|
+
| `TRANSACTION_TIMEOUT` | `number` | `30000` (ms) |
|
|
174
|
+
| `DB_DEBUG_TRACE` | `boolean` | `false` |
|
|
175
|
+
|
|
176
|
+
### Drizzle ORM
|
|
177
|
+
|
|
178
|
+
| Variable | Type | Default |
|
|
179
|
+
|----------|------|---------|
|
|
180
|
+
| `DRIZZLE_SCHEMA_PATH` | `string` | `'./src/server/entities/config.ts'` |
|
|
181
|
+
| `DRIZZLE_OUT_DIR` | `string` | `'./drizzle'` |
|
|
182
|
+
|
|
183
|
+
### Logger
|
|
184
|
+
|
|
185
|
+
| Variable | Type | Default |
|
|
186
|
+
|----------|------|---------|
|
|
187
|
+
| `SPFN_LOG_LEVEL` | `'debug' \| 'info' \| 'warn' \| 'error' \| 'fatal'` | `'info'` |
|
|
188
|
+
|
|
189
|
+
### Cache (Redis/Valkey) — all optional
|
|
190
|
+
|
|
191
|
+
| Variable | Type | `sensitive` | Validator |
|
|
192
|
+
|----------|------|-------------|-----------|
|
|
193
|
+
| `CACHE_URL` | `string` | yes | `parseRedisUrl` |
|
|
194
|
+
| `CACHE_WRITE_URL` | `string` | yes | `parseRedisUrl` |
|
|
195
|
+
| `CACHE_READ_URL` | `string` | yes | `parseRedisUrl` |
|
|
196
|
+
| `CACHE_SENTINEL_HOSTS` | `string` | no | — (comma-separated hosts) |
|
|
197
|
+
| `CACHE_CLUSTER_NODES` | `string` | no | — (comma-separated nodes) |
|
|
198
|
+
| `CACHE_MASTER_NAME` | `string` | no | — (Sentinel master name) |
|
|
199
|
+
| `CACHE_PASSWORD` | `string` | yes | — |
|
|
200
|
+
| `CACHE_TLS_REJECT_UNAUTHORIZED` | `boolean` | — | default `true` |
|
|
201
|
+
|
|
202
|
+
> These four patterns are mutually exclusive at the connection layer (single / master-replica
|
|
203
|
+
> / sentinel / cluster) — the schema does not enforce that; it only validates individual values.
|
|
204
|
+
|
|
205
|
+
### Server
|
|
206
|
+
|
|
207
|
+
| Variable | Type | Default |
|
|
208
|
+
|----------|------|---------|
|
|
209
|
+
| `PORT` | `number` | `4000` |
|
|
210
|
+
| `HOST` | `string` | `'localhost'` |
|
|
211
|
+
| `SERVER_TIMEOUT` | `number` | `120000` (ms) |
|
|
212
|
+
| `SERVER_KEEPALIVE_TIMEOUT` | `number` | `65000` (ms) |
|
|
213
|
+
| `SERVER_HEADERS_TIMEOUT` | `number` | `60000` (ms) |
|
|
214
|
+
| `SHUTDOWN_TIMEOUT` | `number` | `280000` (ms) — must be < k8s `terminationGracePeriodSeconds` minus preStop sleep |
|
|
215
|
+
|
|
216
|
+
### Fetch (outbound HTTP via Node `undici`)
|
|
217
|
+
|
|
218
|
+
| Variable | Type | Default |
|
|
219
|
+
|----------|------|---------|
|
|
220
|
+
| `FETCH_CONNECT_TIMEOUT` | `number` | `10000` (ms) |
|
|
221
|
+
| `FETCH_HEADERS_TIMEOUT` | `number` | `300000` (ms) |
|
|
222
|
+
| `FETCH_BODY_TIMEOUT` | `number` | `300000` (ms) |
|
|
223
|
+
|
|
224
|
+
### Next.js integration
|
|
225
|
+
|
|
226
|
+
| Variable | Type | Required | Validator | Notes |
|
|
227
|
+
|----------|------|----------|-----------|-------|
|
|
228
|
+
| `SPFN_API_URL` | `string` (`envUrl`) | **Yes** | URL | `nextjs: true`; Next.js → backend |
|
|
229
|
+
| `NEXT_PUBLIC_SPFN_API_URL` | `string` (`envUrl`) | No | URL | `nextjs: true`; client-exposed, inlined by Next.js at build; the server uses `SPFN_API_URL` |
|
|
230
|
+
| `SPFN_APP_URL` | `string` (`envUrl`) | No (no default) | URL | `nextjs: true`; SPFN server → Next.js |
|
|
231
|
+
| `RPC_PROXY_TIMEOUT` | `number` | No (default `120000`) | — | `nextjs: true`; keep < `FETCH_HEADERS_TIMEOUT` |
|
|
232
|
+
|
|
233
|
+
> `SPFN_API_URL` is **required** — a missing or non-URL value throws on first access.
|
|
234
|
+
> `NEXT_PUBLIC_SPFN_API_URL` is optional to the server, which falls back to `SPFN_API_URL`;
|
|
235
|
+
> set it wherever browser code needs the API URL. These three URLs are declared by
|
|
236
|
+
> `@spfn/core` only — packages read them from `@spfn/core/config` rather than declaring them again.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Pitfalls & anti-patterns
|
|
241
|
+
|
|
242
|
+
- **Don't expect validation on import.** Importing `@spfn/core/config` validates nothing;
|
|
243
|
+
the proxy validates each variable on property access. A missing `SPFN_API_URL` throws
|
|
244
|
+
when you *read* it, not when you import `env`. The SPFN server does check it eagerly at
|
|
245
|
+
boot (`startServer` / `createServerlessApp`), so a server process needs it set.
|
|
246
|
+
- **The three URLs are validated as URLs (`envUrl`).** A non-URL string in `SPFN_API_URL`,
|
|
247
|
+
`NEXT_PUBLIC_SPFN_API_URL` or `SPFN_APP_URL` fails on access and at boot.
|
|
248
|
+
- **Don't call `loadEnv()` inside Next.js.** Next.js already loads `.env*`. Calling it there
|
|
249
|
+
(with `server: true`) would pull `.env.server` secrets into the Next.js process. In the
|
|
250
|
+
**SPFN server** entry point you *do* call `loadEnv()` before touching `env`.
|
|
251
|
+
- **The schema is fixed — don't try to add app variables here.** `coreEnvSchema` covers only
|
|
252
|
+
`@spfn/core`'s own variables. For your application's variables, define a separate schema
|
|
253
|
+
and registry via `@spfn/core/env` (`defineEnvSchema` + `createEnvRegistry`); validate both
|
|
254
|
+
registries together with `validateAllEnv([coreRegistry, appRegistry])`.
|
|
255
|
+
- **`env` vs `envSchema`.** `env.DB_POOL_MAX` is the resolved value (`number`);
|
|
256
|
+
`envSchema.DB_POOL_MAX` is the schema entry (read `.default` / `.description` / `.examples`).
|
|
257
|
+
Don't read values off `envSchema` or metadata off `env`.
|
|
258
|
+
- **`CACHE_*` / `DATABASE_*` URLs are validated.** A present-but-malformed value throws via
|
|
259
|
+
`parseRedisUrl` / `parsePostgresUrl` on access — these are not free-form strings.
|
|
260
|
+
- **No config-specific loader.** This module re-exports nothing from `@spfn/core/env`. Import
|
|
261
|
+
`loadEnv` from `@spfn/core/env/loader`, parsers/guards from `@spfn/core/env`.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Complete example
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
// SPFN server entry point
|
|
269
|
+
import { loadEnv } from '@spfn/core/env/loader';
|
|
270
|
+
import { env, registry } from '@spfn/core/config';
|
|
271
|
+
|
|
272
|
+
loadEnv(); // populate process.env from .env* (server includes .env.server)
|
|
273
|
+
|
|
274
|
+
// Eager gate for a custom entry point — startServer() already runs this check
|
|
275
|
+
// (see "Boot-time check" in the env README), so an SPFN server needs none of it.
|
|
276
|
+
const { errors, warnings } = registry.validateAll();
|
|
277
|
+
for (const w of warnings) console.warn(`${w.key}: ${w.message}`);
|
|
278
|
+
if (errors.length)
|
|
279
|
+
{
|
|
280
|
+
for (const e of errors) console.error(`${e.key}: ${e.message}`);
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Lazily-validated reads:
|
|
285
|
+
const server =
|
|
286
|
+
{
|
|
287
|
+
port: env.PORT, // 4000 (default)
|
|
288
|
+
host: env.HOST, // 'localhost' (default)
|
|
289
|
+
requestTimeout: env.SERVER_TIMEOUT, // 120000 (default)
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const db =
|
|
293
|
+
{
|
|
294
|
+
url: env.DATABASE_URL, // string | undefined
|
|
295
|
+
poolMax: env.DB_POOL_MAX, // 10 (default)
|
|
296
|
+
monitoring: env.DB_MONITORING_ENABLED // false (default)
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
const apiUrl = env.SPFN_API_URL; // required URL — throws if unset/invalid
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
// Next.js — no loadEnv()
|
|
304
|
+
import { env } from '@spfn/core/config';
|
|
305
|
+
|
|
306
|
+
const apiUrl = env.NEXT_PUBLIC_SPFN_API_URL; // optional URL, client-exposed
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
// Reset the validated flag (tests only)
|
|
311
|
+
import { registry } from '@spfn/core/config';
|
|
312
|
+
registry.reset();
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Types reference
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
// env's element types come straight from coreEnvSchema via InferEnvType:
|
|
321
|
+
type NodeEnv = 'local' | 'development' | 'staging' | 'production' | 'test';
|
|
322
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
323
|
+
// `typeof env` = InferEnvType<typeof coreEnvSchema> (see @spfn/core/env)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Related
|
|
327
|
+
|
|
328
|
+
- [@spfn/core/env](../env/README.md) — the schema DSL, parsers, registry, type guards, and
|
|
329
|
+
`loadEnv` that this module is built on. **Read this for everything not specific to
|
|
330
|
+
`coreEnvSchema`.**
|
|
331
|
+
- [@spfn/core/logger](../logger/README.md) — consumes `SPFN_LOG_LEVEL`.
|
|
332
|
+
- [@spfn/core/db](../db/README.md) — consumes the `DATABASE_*` / `DB_*` variables.
|
|
333
|
+
- [@spfn/core](../../README.md) — main package documentation.
|