celery-env 0.1.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/LICENSE +21 -0
- package/README.md +151 -0
- package/SECURITY.md +75 -0
- package/docs/BENCHMARKS.md +44 -0
- package/docs/CLI.md +68 -0
- package/docs/COMPARISON.md +58 -0
- package/docs/GETTING_STARTED.md +134 -0
- package/docs/MIGRATION.md +54 -0
- package/docs/README.md +15 -0
- package/docs/RUNTIME.md +43 -0
- package/docs/SCHEMA.md +149 -0
- package/docs/TROUBLESHOOTING.md +74 -0
- package/docs/TYPESCRIPT.md +105 -0
- package/docs/assets/celery-mark.svg +7 -0
- package/package.json +77 -0
- package/src/cli.js +133 -0
- package/src/compiler.d.ts +7 -0
- package/src/compiler.js +811 -0
- package/src/index.d.ts +22 -0
- package/src/index.js +375 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# celery-env
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="docs/assets/celery-mark.svg" alt="celery-env" width="96" height="96">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Environment validation that compiles to tiny standalone JavaScript.</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/celery-env"><img alt="npm" src="https://img.shields.io/npm/v/celery-env?color=0f766e"></a>
|
|
13
|
+
<a href="https://github.com/theaaravagarwal/celery-env/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/theaaravagarwal/celery-env/ci.yml?branch=main"></a>
|
|
14
|
+
<img alt="dependencies" src="https://img.shields.io/badge/dependencies-0-0f766e">
|
|
15
|
+
<a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-black"></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
Celery validates `process.env` with a schema you can read, then generates a
|
|
19
|
+
small validator you can ship without a runtime dependency. It is built for app
|
|
20
|
+
configuration: defaults, production-only secrets, typed output, good error
|
|
21
|
+
messages, and fast startup.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npm install -D celery-env
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Other package managers:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
pnpm add -D celery-env
|
|
33
|
+
yarn add -D celery-env
|
|
34
|
+
bun add -d celery-env
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 60-Second Setup
|
|
38
|
+
|
|
39
|
+
Create a schema:
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
// env.schema.mjs
|
|
43
|
+
import { bool, defineEnv, int, oneOf, str, url } from "celery-env";
|
|
44
|
+
|
|
45
|
+
export default defineEnv({
|
|
46
|
+
NODE_ENV: oneOf(["development", "test", "production"], { default: "development" }),
|
|
47
|
+
DATABASE_URL: url({ protocols: ["postgres"] }),
|
|
48
|
+
PORT: int({ default: 3000, min: 1, max: 65535 }),
|
|
49
|
+
DEBUG: bool({ default: false }),
|
|
50
|
+
SESSION_SECRET: str({
|
|
51
|
+
optional: true,
|
|
52
|
+
requiredWhen: (env) => env.NODE_ENV === "production"
|
|
53
|
+
})
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Generate the validator:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
npx celery-env generate \
|
|
61
|
+
--schema env.schema.mjs \
|
|
62
|
+
--out src/env.mjs \
|
|
63
|
+
--types src/env.d.ts \
|
|
64
|
+
--example .env.example \
|
|
65
|
+
--minify
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Use it at app startup:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
// src/config.js
|
|
72
|
+
import { loadEnv } from "./env.mjs";
|
|
73
|
+
|
|
74
|
+
export const env = loadEnv(process.env);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
That is the main path: write `env.schema.mjs`, generate `src/env.mjs`, and use
|
|
78
|
+
the typed result everywhere else.
|
|
79
|
+
|
|
80
|
+
## When To Use Celery
|
|
81
|
+
|
|
82
|
+
Use Celery when you want env validation to be:
|
|
83
|
+
|
|
84
|
+
- focused on app configuration instead of general object validation;
|
|
85
|
+
- generated once and cheap at startup;
|
|
86
|
+
- dependency-free in production;
|
|
87
|
+
- typed without hand-written config types;
|
|
88
|
+
- strict about missing production secrets without printing secret values.
|
|
89
|
+
|
|
90
|
+
If you already use Zod for forms, API payloads, or general data validation,
|
|
91
|
+
keep using it there. Celery is for the narrower `process.env` problem where
|
|
92
|
+
defaults, examples, generated files, and startup cost matter.
|
|
93
|
+
|
|
94
|
+
## Why Use It
|
|
95
|
+
|
|
96
|
+
- **Generated validator**: no schema walk during app startup.
|
|
97
|
+
- **Zero runtime dependencies** in generated mode.
|
|
98
|
+
- **Small output**: the measured small generated validator is 526 gzip bytes.
|
|
99
|
+
- **Typed config** through generated `.d.ts` files or `InferEnv`.
|
|
100
|
+
- **Env-specific rules** like `devDefault`, `testDefault`, and `requiredWhen`.
|
|
101
|
+
- **Secret-safe errors** that do not print rejected secret values.
|
|
102
|
+
- **Runtime mode** available when you do not want a build step.
|
|
103
|
+
|
|
104
|
+
## Runtime Mode
|
|
105
|
+
|
|
106
|
+
Generated mode is recommended for apps, but direct parsing is available:
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
import { defineEnv, int, parseEnv, str } from "celery-env";
|
|
110
|
+
|
|
111
|
+
const schema = defineEnv({
|
|
112
|
+
DATABASE_URL: str({ min: 1 }),
|
|
113
|
+
PORT: int({ default: 3000 })
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
export const env = parseEnv(schema, process.env);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Benchmarks
|
|
120
|
+
|
|
121
|
+
Current report: Node v26.3.0, macOS arm64, Apple M3.
|
|
122
|
+
|
|
123
|
+
| Metric | Result |
|
|
124
|
+
| --- | ---: |
|
|
125
|
+
| Valid real-schema geometric mean | 1.50x over best external competitor |
|
|
126
|
+
| Real `process.env` geometric mean | 1.14x over best external competitor |
|
|
127
|
+
| Invalid real-schema geometric mean | 1.32x over best external competitor |
|
|
128
|
+
| Cold first validation | 2.42x faster than best external competitor |
|
|
129
|
+
| Generated validator size | 526 gzip bytes |
|
|
130
|
+
| Smallest external bundle gap | 2.15x smaller |
|
|
131
|
+
|
|
132
|
+
Competitors measured include Zod, Valibot, Envalid, Envsafe, env-var, T3 Env
|
|
133
|
+
Core, Valienv, env-schema, env-type-validator, safe-env-vars, and Convict where
|
|
134
|
+
the benchmark applies. The claim is specific to this env-validation corpus.
|
|
135
|
+
|
|
136
|
+
## Documentation
|
|
137
|
+
|
|
138
|
+
- [Getting Started](docs/GETTING_STARTED.md)
|
|
139
|
+
- [Schema API](docs/SCHEMA.md)
|
|
140
|
+
- [CLI](docs/CLI.md)
|
|
141
|
+
- [TypeScript](docs/TYPESCRIPT.md)
|
|
142
|
+
- [Runtime Mode](docs/RUNTIME.md)
|
|
143
|
+
- [Comparison](docs/COMPARISON.md)
|
|
144
|
+
- [Troubleshooting](docs/TROUBLESHOOTING.md)
|
|
145
|
+
- [Benchmarks](docs/BENCHMARKS.md)
|
|
146
|
+
- [Migration Guide](docs/MIGRATION.md)
|
|
147
|
+
- [Security](SECURITY.md)
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
MIT
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
`celery-env` is designed to keep the published package small and auditable:
|
|
4
|
+
|
|
5
|
+
- The root package has zero runtime dependencies.
|
|
6
|
+
- The package has no consumer install hooks or pack hooks. Its only publish
|
|
7
|
+
lifecycle script is `prepublishOnly`, which runs the local verification gate.
|
|
8
|
+
- Runtime validation does not include rejected environment values in error messages.
|
|
9
|
+
- Generated validators escape schema keys and validate generated function names.
|
|
10
|
+
- Environment reads require own properties, so inherited object-prototype keys do
|
|
11
|
+
not masquerade as environment variables.
|
|
12
|
+
- Generated `requiredWhen` predicates receive an own-property environment facade
|
|
13
|
+
instead of the raw inherited object.
|
|
14
|
+
- `__proto__` schema keys are treated as data properties instead of prototype mutation.
|
|
15
|
+
- Publish validation uses `npm pack --ignore-scripts`; local hardening checks
|
|
16
|
+
reject consumer install hooks, pack hooks, and unexpected publish hooks.
|
|
17
|
+
- CLI generation refuses symlink outputs and only overwrites existing generated
|
|
18
|
+
files when `--force` is passed.
|
|
19
|
+
|
|
20
|
+
## Audit Commands
|
|
21
|
+
|
|
22
|
+
Run the local hardening checks before publishing:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npm run security:scan
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The root package intentionally has no lockfile because it has no dependencies.
|
|
29
|
+
`npm audit` requires a lockfile, so root-package supply-chain checks are covered
|
|
30
|
+
by `scripts/security-scan.mjs` and `scripts/validate-publish.mjs`.
|
|
31
|
+
|
|
32
|
+
CI runs the same root hardening scan on Node 18, 20, 22, and 26.
|
|
33
|
+
|
|
34
|
+
## Hardening Findings
|
|
35
|
+
|
|
36
|
+
The dependency audit did not find known vulnerable packages. The hardening pass
|
|
37
|
+
did find code-level weakness classes before release, and they are now covered by
|
|
38
|
+
tests:
|
|
39
|
+
|
|
40
|
+
- Prototype-polluted option objects could make missing values optional or inject
|
|
41
|
+
defaults. Specs now use null-prototype rule objects and own-property checks.
|
|
42
|
+
- `requiredWhen` predicates could observe inherited env properties. Predicates
|
|
43
|
+
now receive an own-property env facade.
|
|
44
|
+
- Generated `json()` validation could be bypassed through inherited
|
|
45
|
+
object/array keys. JSON parse success no longer depends on target-slot
|
|
46
|
+
sentinel values.
|
|
47
|
+
- Generated function names missed some strict-mode forbidden identifiers. Those
|
|
48
|
+
names are now rejected.
|
|
49
|
+
- Non-expression `requiredWhen` functions could emit invalid generated code.
|
|
50
|
+
They are now rejected at generation time.
|
|
51
|
+
- Non-JSON-stable `json()` defaults could diverge between runtime and generated
|
|
52
|
+
validators. They are now rejected for generated output.
|
|
53
|
+
- CLI generation could overwrite requested output paths. It now requires
|
|
54
|
+
`--force` and refuses symlink outputs.
|
|
55
|
+
|
|
56
|
+
## Trust Boundary
|
|
57
|
+
|
|
58
|
+
Schema files and `requiredWhen` predicates are application code. The CLI imports
|
|
59
|
+
the schema file you pass with `--schema`, and generated validators serialize
|
|
60
|
+
`requiredWhen` function source. Only run generation against schema files and
|
|
61
|
+
predicates you trust; do not generate validators from untrusted schema packages.
|
|
62
|
+
|
|
63
|
+
Generated `.env.example` output is documentation. It escapes unsafe key/value
|
|
64
|
+
line breaks, but it still reflects schema-provided `example`, `default`,
|
|
65
|
+
`devDefault`, `testDefault`, `desc`, and `docs` metadata. Do not put real
|
|
66
|
+
secrets in schema defaults or examples that you plan to publish.
|
|
67
|
+
|
|
68
|
+
## Reporting
|
|
69
|
+
|
|
70
|
+
Report security issues privately through GitHub Security Advisories:
|
|
71
|
+
|
|
72
|
+
https://github.com/theaaravagarwal/celery-env/security/advisories/new
|
|
73
|
+
|
|
74
|
+
Include a minimal reproduction, the affected version, and whether the issue
|
|
75
|
+
affects runtime validation, generated validators, or CLI generation.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Benchmarks
|
|
2
|
+
|
|
3
|
+
Benchmark dependencies are kept out of the root package so `celery-env` stays
|
|
4
|
+
dependency-free. The public package ships the headline report and claim rules,
|
|
5
|
+
not the local benchmark lab.
|
|
6
|
+
|
|
7
|
+
## Current Headline
|
|
8
|
+
|
|
9
|
+
Current report: Node v26.3.0, macOS arm64, Apple M3.
|
|
10
|
+
|
|
11
|
+
| Metric | Result |
|
|
12
|
+
| --- | ---: |
|
|
13
|
+
| Valid real-schema geometric mean | 1.50x over best external competitor |
|
|
14
|
+
| Real `process.env` geometric mean | 1.14x over best external competitor |
|
|
15
|
+
| Invalid real-schema geometric mean | 1.32x over best external competitor |
|
|
16
|
+
| Cold first validation | 2.42x faster than best external competitor |
|
|
17
|
+
| Generated validator size | 526 gzip bytes |
|
|
18
|
+
| Smallest external bundle gap | 2.15x smaller |
|
|
19
|
+
|
|
20
|
+
## What Is Measured
|
|
21
|
+
|
|
22
|
+
- Synthetic small, medium, and large schemas.
|
|
23
|
+
- Realistic API, web, worker, list-heavy, and JSON-heavy env schemas.
|
|
24
|
+
- Frozen plain env objects and real `process.env`.
|
|
25
|
+
- Invalid input with aggregate errors.
|
|
26
|
+
- Cold import/setup/first validation.
|
|
27
|
+
- Shipped gzip bundle size.
|
|
28
|
+
|
|
29
|
+
## Competitors
|
|
30
|
+
|
|
31
|
+
The benchmark corpus includes Zod, Valibot, Envalid, Envsafe, env-var, T3 Env
|
|
32
|
+
Core, Valienv, env-schema, env-type-validator, safe-env-vars, and Convict where
|
|
33
|
+
the benchmark applies.
|
|
34
|
+
|
|
35
|
+
## Claim Rules
|
|
36
|
+
|
|
37
|
+
Use precise benchmark claims:
|
|
38
|
+
|
|
39
|
+
- Good: "1.50x over the best external competitor on the real-schema corpus."
|
|
40
|
+
- Good: "526 gzip bytes for the measured small generated validator."
|
|
41
|
+
- Avoid: "Celery is always 50x faster."
|
|
42
|
+
|
|
43
|
+
Env validation is workload-dependent, especially when reading real
|
|
44
|
+
`process.env`.
|
package/docs/CLI.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# CLI
|
|
2
|
+
|
|
3
|
+
The CLI creates schemas and generated validator files.
|
|
4
|
+
|
|
5
|
+
## Initialize A Schema
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npx celery-env init --target node --schema env.schema.mjs
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Use `init` when starting from scratch. It writes a small schema with common
|
|
12
|
+
Node app variables.
|
|
13
|
+
|
|
14
|
+
Targets:
|
|
15
|
+
|
|
16
|
+
| Target | Use For |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| `node` | Regular Node apps and services. |
|
|
19
|
+
| `next` | Next.js projects. |
|
|
20
|
+
| `vite` | Vite projects and edge-style environments. |
|
|
21
|
+
|
|
22
|
+
## Generate
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npx celery-env generate \
|
|
26
|
+
--schema env.schema.mjs \
|
|
27
|
+
--out src/env.mjs \
|
|
28
|
+
--types src/env.d.ts \
|
|
29
|
+
--example .env.example
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Use `generate` after editing `env.schema.mjs`.
|
|
33
|
+
|
|
34
|
+
## Flags
|
|
35
|
+
|
|
36
|
+
| Flag | Meaning |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `--schema <file>` | Schema module to import. |
|
|
39
|
+
| `--out <file>` | Generated validator output path. |
|
|
40
|
+
| `--types <file>` | Generated `.d.ts` output path. |
|
|
41
|
+
| `--example <file>` | Generated `.env.example` output path. |
|
|
42
|
+
| `--function-name <name>` | Generated function name. Default: `loadEnv`. |
|
|
43
|
+
| `--no-process-default` | Do not default to `process.env` in generated output. |
|
|
44
|
+
| `--minify` | Emit smaller generated JavaScript. |
|
|
45
|
+
| `--fail-fast` | Throw on the first error instead of aggregating errors. |
|
|
46
|
+
| `--force` | Overwrite existing generated files. |
|
|
47
|
+
| `--optimize speed` | Emit larger speed-prioritized code for supported cases. |
|
|
48
|
+
|
|
49
|
+
## Recommended App Command
|
|
50
|
+
|
|
51
|
+
Add a script:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"scripts": {
|
|
56
|
+
"env:generate": "celery-env generate --schema env.schema.mjs --out src/env.mjs --types src/env.d.ts --example .env.example --minify"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Run it whenever the schema changes:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npm run env:generate
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Generated files are regular source files. Commit them when you want production
|
|
68
|
+
deployments to run without the generator.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Comparison
|
|
2
|
+
|
|
3
|
+
Celery is not a replacement for general validation libraries. It is a focused
|
|
4
|
+
tool for environment configuration.
|
|
5
|
+
|
|
6
|
+
## Celery vs Zod
|
|
7
|
+
|
|
8
|
+
Zod is excellent for general TypeScript validation: forms, API payloads,
|
|
9
|
+
domain objects, JSON data, and reusable schemas across an app.
|
|
10
|
+
|
|
11
|
+
Celery is narrower. It validates `process.env`, then can generate a standalone
|
|
12
|
+
validator and declaration file for production startup.
|
|
13
|
+
|
|
14
|
+
| Question | Celery | Zod |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| Main job | Validate env config. | Validate general data. |
|
|
17
|
+
| Schema shape | One key per env var. | Any object/data shape. |
|
|
18
|
+
| Generated validator | Yes. | No. |
|
|
19
|
+
| Production runtime dependency | None in generated mode. | `zod`. |
|
|
20
|
+
| `.env.example` generation | Built in. | Build yourself. |
|
|
21
|
+
| Env-specific defaults | Built in. | Build yourself. |
|
|
22
|
+
| Secret-safe env errors | Built in. | Build yourself. |
|
|
23
|
+
| Ecosystem size | Small and focused. | Large and mature. |
|
|
24
|
+
|
|
25
|
+
Use Zod when you need general validation. Use Celery when the thing being
|
|
26
|
+
validated is application configuration.
|
|
27
|
+
|
|
28
|
+
## Celery vs Envalid / Envsafe / env-var
|
|
29
|
+
|
|
30
|
+
These libraries are purpose-built for env validation and are good defaults for
|
|
31
|
+
runtime validation.
|
|
32
|
+
|
|
33
|
+
Celery's main difference is generated mode:
|
|
34
|
+
|
|
35
|
+
- the schema stays in development code;
|
|
36
|
+
- the generated validator can be committed;
|
|
37
|
+
- production can run without loading the schema library;
|
|
38
|
+
- TypeScript declarations can be generated from the same schema;
|
|
39
|
+
- `.env.example` can be generated from schema metadata.
|
|
40
|
+
|
|
41
|
+
## Choosing A Mode
|
|
42
|
+
|
|
43
|
+
| Use Case | Recommended Mode |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| Production app or service | Generated |
|
|
46
|
+
| Serverless or cold-start-sensitive app | Generated |
|
|
47
|
+
| CLI script or small internal tool | Runtime |
|
|
48
|
+
| Prototype before deciding schema shape | Runtime |
|
|
49
|
+
| App with no build/generate step allowed | Runtime |
|
|
50
|
+
|
|
51
|
+
## What Celery Does Not Do
|
|
52
|
+
|
|
53
|
+
- It does not load `.env` files. Use your platform, shell, or a dotenv loader.
|
|
54
|
+
- It does not validate arbitrary request bodies or form data.
|
|
55
|
+
- It does not validate the internal shape of `json()` values.
|
|
56
|
+
- It does not make untrusted schema files safe to execute.
|
|
57
|
+
|
|
58
|
+
Schema files are application code.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
This guide assumes you have a Node project and want one reliable place to define
|
|
4
|
+
environment variables.
|
|
5
|
+
|
|
6
|
+
## 1. Install
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm install -D celery-env
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
pnpm add -D celery-env
|
|
14
|
+
yarn add -D celery-env
|
|
15
|
+
bun add -d celery-env
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Use a dev dependency when you generate validators. The generated output has no
|
|
19
|
+
runtime dependency on `celery-env`.
|
|
20
|
+
|
|
21
|
+
## 2. Create A Schema
|
|
22
|
+
|
|
23
|
+
Create `env.schema.mjs` in your project root:
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
import { bool, defineEnv, int, oneOf, str, url } from "celery-env";
|
|
27
|
+
|
|
28
|
+
export default defineEnv({
|
|
29
|
+
NODE_ENV: oneOf(["development", "test", "production"], {
|
|
30
|
+
default: "development"
|
|
31
|
+
}),
|
|
32
|
+
|
|
33
|
+
DATABASE_URL: url({
|
|
34
|
+
protocols: ["postgres"]
|
|
35
|
+
}),
|
|
36
|
+
|
|
37
|
+
PORT: int({
|
|
38
|
+
default: 3000,
|
|
39
|
+
min: 1,
|
|
40
|
+
max: 65535
|
|
41
|
+
}),
|
|
42
|
+
|
|
43
|
+
DEBUG: bool({
|
|
44
|
+
default: false
|
|
45
|
+
}),
|
|
46
|
+
|
|
47
|
+
SESSION_SECRET: str({
|
|
48
|
+
optional: true,
|
|
49
|
+
requiredWhen: (env) => env.NODE_ENV === "production",
|
|
50
|
+
desc: "Required in production."
|
|
51
|
+
})
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 3. Generate The Validator
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
npx celery-env generate \
|
|
59
|
+
--schema env.schema.mjs \
|
|
60
|
+
--out src/env.mjs \
|
|
61
|
+
--types src/env.d.ts \
|
|
62
|
+
--example .env.example \
|
|
63
|
+
--minify
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This creates:
|
|
67
|
+
|
|
68
|
+
| File | Purpose |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| `src/env.mjs` | Runtime validator used by your app. |
|
|
71
|
+
| `src/env.d.ts` | Types for editors and TypeScript. |
|
|
72
|
+
| `.env.example` | Documented env template. |
|
|
73
|
+
|
|
74
|
+
Add the command to `package.json` so the workflow is repeatable:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"scripts": {
|
|
79
|
+
"env:generate": "celery-env generate --schema env.schema.mjs --out src/env.mjs --types src/env.d.ts --example .env.example --minify"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 4. Load Env Once
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
import { loadEnv } from "./env.mjs";
|
|
88
|
+
|
|
89
|
+
export const env = loadEnv(process.env);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Use `env` everywhere else instead of reading `process.env` directly.
|
|
93
|
+
|
|
94
|
+
## 5. Use A Nested App Config
|
|
95
|
+
|
|
96
|
+
If your app already expects a nested config object, keep the generated env flat
|
|
97
|
+
and adapt it in one small file:
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
import { loadEnv } from "./env.mjs";
|
|
101
|
+
|
|
102
|
+
export function loadConfig(source = process.env) {
|
|
103
|
+
const env = loadEnv(source);
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
app: {
|
|
107
|
+
nodeEnv: env.NODE_ENV,
|
|
108
|
+
port: env.PORT
|
|
109
|
+
},
|
|
110
|
+
database: {
|
|
111
|
+
url: env.DATABASE_URL
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## What To Commit
|
|
118
|
+
|
|
119
|
+
For most apps, commit all of these:
|
|
120
|
+
|
|
121
|
+
- `env.schema.mjs`
|
|
122
|
+
- `src/env.mjs`
|
|
123
|
+
- `src/env.d.ts`
|
|
124
|
+
- `.env.example`
|
|
125
|
+
|
|
126
|
+
Committing generated files keeps deployments simple because production does not
|
|
127
|
+
need to run the generator.
|
|
128
|
+
|
|
129
|
+
## Next Steps
|
|
130
|
+
|
|
131
|
+
- Read [Schema API](SCHEMA.md) when adding validators.
|
|
132
|
+
- Read [TypeScript](TYPESCRIPT.md) if editor types do not look right.
|
|
133
|
+
- Read [Troubleshooting](TROUBLESHOOTING.md) if generation or URL validation
|
|
134
|
+
fails.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Migration Guide
|
|
2
|
+
|
|
3
|
+
Use this guide when adding Celery to an existing app.
|
|
4
|
+
|
|
5
|
+
## Step 1. Find Env Reads
|
|
6
|
+
|
|
7
|
+
Search for direct env access:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
rg "process\\.env|env\\.[A-Z_]+"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The goal is one central module that reads env and exports validated config.
|
|
14
|
+
|
|
15
|
+
## Step 2. Write A Flat Schema
|
|
16
|
+
|
|
17
|
+
Keep schema keys close to actual env var names:
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import { defineEnv, int, oneOf, url } from "celery-env";
|
|
21
|
+
|
|
22
|
+
export default defineEnv({
|
|
23
|
+
NODE_ENV: oneOf(["development", "test", "production"], { default: "development" }),
|
|
24
|
+
DATABASE_URL: url({ protocols: ["postgres"] }),
|
|
25
|
+
PORT: int({ default: 3000 })
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Step 3. Generate
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
npx celery-env generate --schema env.schema.mjs --out src/env.mjs --types src/env.d.ts --example .env.example --minify
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Step 4. Keep Your Existing Shape
|
|
36
|
+
|
|
37
|
+
If your app already expects nested config, adapt once:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import { loadEnv } from "./env.mjs";
|
|
41
|
+
|
|
42
|
+
export function loadConfig(source = process.env) {
|
|
43
|
+
const env = loadEnv(source);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
app: { port: env.PORT },
|
|
47
|
+
database: { url: env.DATABASE_URL }
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Step 5. Remove Direct Env Reads
|
|
53
|
+
|
|
54
|
+
Use the validated config everywhere else.
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# celery-env Documentation
|
|
2
|
+
|
|
3
|
+
Start here if you are new to Celery or new to typed env validation.
|
|
4
|
+
|
|
5
|
+
## Learning Path
|
|
6
|
+
|
|
7
|
+
1. [Getting Started](GETTING_STARTED.md): install, write a schema, generate a validator.
|
|
8
|
+
2. [Schema API](SCHEMA.md): every validator and option.
|
|
9
|
+
3. [CLI](CLI.md): `init`, `generate`, and generation flags.
|
|
10
|
+
4. [TypeScript](TYPESCRIPT.md): generated types and `InferEnv`.
|
|
11
|
+
5. [Runtime Mode](RUNTIME.md): use Celery without generation.
|
|
12
|
+
6. [Comparison](COMPARISON.md): when to use Celery instead of general validators.
|
|
13
|
+
7. [Troubleshooting](TROUBLESHOOTING.md): common setup and generation issues.
|
|
14
|
+
8. [Migration Guide](MIGRATION.md): add Celery to an existing project.
|
|
15
|
+
9. [Benchmarks](BENCHMARKS.md): what is measured and what claims are safe.
|
package/docs/RUNTIME.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Runtime Mode
|
|
2
|
+
|
|
3
|
+
Runtime mode validates with `parseEnv(schema, env)` directly. Use it when:
|
|
4
|
+
|
|
5
|
+
- You do not want generated files.
|
|
6
|
+
- Your app is small and startup cost is not critical.
|
|
7
|
+
- You are prototyping before switching to generated mode.
|
|
8
|
+
|
|
9
|
+
## Example
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import { defineEnv, int, parseEnv, str } from "celery-env";
|
|
13
|
+
|
|
14
|
+
const schema = defineEnv({
|
|
15
|
+
DATABASE_URL: str({ min: 1 }),
|
|
16
|
+
PORT: int({ default: 3000 })
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const env = parseEnv(schema, process.env);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Tradeoff
|
|
23
|
+
|
|
24
|
+
Runtime mode is simpler, but generated mode is usually faster and can avoid a
|
|
25
|
+
runtime dependency in production.
|
|
26
|
+
|
|
27
|
+
| Mode | Build Step | Runtime Dependency | Best For |
|
|
28
|
+
| --- | --- | --- | --- |
|
|
29
|
+
| Generated | yes | no | production apps |
|
|
30
|
+
| Runtime | no | yes | small apps, scripts, prototypes |
|
|
31
|
+
|
|
32
|
+
## Errors
|
|
33
|
+
|
|
34
|
+
Celery aggregates errors by default:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
Invalid environment:
|
|
38
|
+
- DATABASE_URL is required
|
|
39
|
+
- PORT must be an integer
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Rejected values are not included in error messages, which helps avoid leaking
|
|
43
|
+
secrets.
|