envapt 4.1.1 → 5.0.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 +122 -0
- package/README.md +58 -946
- package/dist/Envapter-CBSM3v-5.cjs +3 -0
- package/dist/Envapter-CBSM3v-5.cjs.map +1 -0
- package/dist/Envapter-D8FEdzBR.mjs +3 -0
- package/dist/Envapter-D8FEdzBR.mjs.map +1 -0
- package/dist/config.cjs +2 -0
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +1 -0
- package/dist/config.d.mts +1 -0
- package/dist/config.mjs +2 -0
- package/dist/config.mjs.map +1 -0
- package/dist/index.cjs +1 -921
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +847 -401
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +1127 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1 -909
- package/dist/index.mjs.map +1 -1
- package/package.json +50 -16
- package/dist/index.d.ts +0 -681
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,127 @@
|
|
|
1
1
|
# envapt
|
|
2
2
|
|
|
3
|
+
## 5.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 9711554: **BREAKING:** array converters now use a phantom-branded `Converters.array({ of?, delimiter? })` builder instead of the `{ delimiter, type }` config object. inference survives variable indirection and union-widening, and bad element values in the raw env value throw `EnvaptError` (`ArrayElementConversionFailed`, code 206) instead of silently substituting the raw string into a wrong-typed array.
|
|
8
|
+
|
|
9
|
+
Migration:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
// before
|
|
13
|
+
@Envapt('PORTS', { converter: { delimiter: ',', type: Converters.Number }, fallback: [] })
|
|
14
|
+
@Envapt('TAGS', { converter: Converters.Array, fallback: [] })
|
|
15
|
+
|
|
16
|
+
// after
|
|
17
|
+
@Envapt('PORTS', { converter: Converters.array({ of: Converters.Number }), fallback: [] })
|
|
18
|
+
@Envapt('TAGS', { converter: Converters.array(), fallback: [] })
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**BREAKING:** `Converters` migrates from a TS `enum` to an `as const` object so envapt source stays compatible with `erasableSyntaxOnly` / Node's native TS execution. call sites are unchanged (`Converters.Number === 'number'` still holds), but `Converters` is no longer usable as a type. use `ConverterToken` instead.
|
|
22
|
+
|
|
23
|
+
**BREAKING:** `Converters.Array` token is gone (use `Converters.array()`). the `ArrayConverter` and `ValidArrayConverterBuiltInType` types are gone (replaced by `ArrayOf<TElement>` and `ArrayElement`).
|
|
24
|
+
|
|
25
|
+
new: `of:` accepts a custom `(raw: string) => T` function. the array element type is inferred from the function's return type, so `Converters.array({ of: (raw) => User.parse(raw) })` types the property as `User[]`.
|
|
26
|
+
|
|
27
|
+
new: `Converters.array({ of: Converters.Time })` accepts `TimeFallback[]` (e.g. `['5s', '10m']`) as a fallback, matching the existing scalar `Converters.Time` asymmetry. string fallbacks are coerced to milliseconds at resolve time.
|
|
28
|
+
|
|
29
|
+
`Envapter.getUsing` now routes through the parser whenever a fallback is provided, so `TimeFallback` / `TimeFallback[]` fallbacks are coerced consistently with the `@Envapt` decorator path. fixes a pre-existing inconsistency where `Envapter.getUsing('MISSING', Converters.Time, '10s')` returned `'10s'` instead of `10000`.
|
|
30
|
+
|
|
31
|
+
- 9711554: Add `Envapter.debug` three-level log toggle. Removes the `debug` key from the env-file options object.
|
|
32
|
+
- New `Envapter.debug = 'silent' | 'warn' | 'verbose'` (default `silent`). Output goes to stderr prefixed with `[envapt]`.
|
|
33
|
+
- New `ENVAPT_DEBUG` env var. Read lazily on first access if the setter was never called; the setter wins after that.
|
|
34
|
+
- `warn` level: failed `.env` reads, unresolved `${VAR}` templates (non-strict path), fallback values used in place of missing env.
|
|
35
|
+
- `verbose` level: everything in `warn` plus effective `.env` paths during cache rebuild, the cache-cleared notice, per-file key counts, and per-key load lines.
|
|
36
|
+
- New `DebugLevel` type re-exported from the package root.
|
|
37
|
+
- Invalid setter values throw `EnvaptError(InvalidUserDefinedConfig)` with a list of the accepted levels.
|
|
38
|
+
- **Breaking**: the `debug` key on the env-file options object is removed. Use `Envapter.debug = 'verbose'` (or `ENVAPT_DEBUG=verbose`) instead. The corresponding `[dotenv]`-prefixed lines are gone; all debug output now flows through the unified `[envapt]` surface.
|
|
39
|
+
|
|
40
|
+
- 9711554: **BREAKING:** dropped `dotenv` as a runtime dependency. envapt now has **zero runtime deps**. A small internal `.env` parser ships inline (`src/Dotenv.ts`) that handles the subset of dotenv semantics envapt actually relies on: KEY=VALUE pairs, `export KEY=...` prefix, single / double / backtick quotes (with `\n`, `\r`, `\t`, `\\`, `\"` escape interpretation for double quotes), multi-line quoted values, inline `# comments`, multiple paths with first-wins (or `override: true`), and `encoding` for non-UTF8 files. End-user behavior is unchanged: the existing test suite (357 tests) passes against the new parser.
|
|
41
|
+
|
|
42
|
+
**BREAKING:** `Envapter.envFileOptions` no longer accepts `quiet` or `DOTENV_KEY`.
|
|
43
|
+
- `quiet` existed only to suppress dotenv's marketing tips. envapt never prints anything from the loader, so the option is meaningless. The default `_userDefinedDotenvConfig` is now `{}` instead of `{ quiet: true }`.
|
|
44
|
+
- `DOTENV_KEY` was for `dotenv-vault` encrypted `.env` files. Not exercised by any envapt test and out of scope for envapt's internal parser. If you need encrypted env files, decrypt them externally and pass the resulting `.env` path to `Envapter.envPaths`.
|
|
45
|
+
|
|
46
|
+
Passing either key to `Envapter.envFileOptions = { ... }` now throws `InvalidUserDefinedConfig` (302). The remaining allowed keys are `encoding` and `override`.
|
|
47
|
+
|
|
48
|
+
**BREAKING:** the env-file options accessor was renamed from `Envapter.dotenvConfig` to `Envapter.envFileOptions` (type `DotenvConfigOptions` to `EnvFileOptions`), since it no longer relates to the dropped `dotenv` package.
|
|
49
|
+
|
|
50
|
+
- 9711554: Add global `Envapter.strict` flag, `required: true` option, and `Envapter.require()` for boot-time existence checks.
|
|
51
|
+
- New `Envapter.strict` flag (default `false`). When enabled: whitespace-only values are treated as missing on read; empty / whitespace items in array converters throw `EmptyArrayElement (207)` instead of being silently filtered; unresolved `${VAR}` placeholders in cached values and `Envapter.resolve` tagged templates throw `MissingEnvValue (305)` instead of being preserved as literal text. Toggling the flag refreshes the cache.
|
|
52
|
+
- New `@Envapt(key, { required: true })` decorator option. Throws `MissingEnvValue` on first access if the env value is missing or empty (post-trim). Independent of global `strict`. Mutually exclusive with `fallback`: combining them fails to match any overload at compile time, and the runtime Validator throws `InvalidUserDefinedConfig (302)` for dynamic objects that bypass the types.
|
|
53
|
+
- New functional options-bag form: `Envapter.getUsing(key, { converter, required: true })` and `Envapter.getWith(key, { converter, required: true })` return the converter's narrowed type (no `| undefined`) and throw `MissingEnvValue` on missing/empty. Positional `(key, converter, fallback?)` form unchanged.
|
|
54
|
+
- New `Envapter.require(...keys)` existence-check helper. Variadic rest signature, always returns `void`. At least one key required (compile-time error via `[string, ...string[]]` tuple if zero args). Collects every missing key into a single error instead of failing one at a time. Resolves templates before checking.
|
|
55
|
+
- New error codes: `EmptyArrayElement (207)` for strict-mode array empties; `MissingEnvValue (305)` for required-key absences, `require()` failures, and strict-mode unresolved templates.
|
|
56
|
+
|
|
57
|
+
### Minor Changes
|
|
58
|
+
|
|
59
|
+
- 9711554: Add `Envapter.baseDir` to anchor `.env` resolution to a directory instead of `process.cwd()`. The auto-cascade, `configureProfiles` paths, and relative `envPaths` resolve against it; absolute paths bypass it. It accepts a directory path or a module location: `import.meta.url` / `import.meta.dirname` (ESM) or `__dirname` (CJS). Left unset, paths resolve against `process.cwd()` as before.
|
|
60
|
+
|
|
61
|
+
This covers monorepos where the process starts from the repository root rather than the package directory, so a package-local `.env` resolves regardless of the working directory.
|
|
62
|
+
|
|
63
|
+
- 9711554: Deprecate the classic positional `@Envapt('KEY', fallback, Converter)` form. It now carries a `@deprecated` JSDoc tag and will be removed in v6; it still works throughout v5. Use the options object: `@Envapt('KEY', { converter, fallback })`.
|
|
64
|
+
- 9711554: Add the `envapt/config` side-effect entry, a drop-in for `dotenv/config`. `import 'envapt/config'` (or `node --import envapt/config`, or `node -r envapt/config` in CommonJS) loads envapt's per-environment `.env` cascade and mirrors every loaded key into `process.env`, with zero dependencies. Also adds `Envapter.load()` to eagerly load the cascade on demand instead of lazily on first read.
|
|
65
|
+
- 9711554: Lowered the Node engine floor from `>=24.0.0` to `>=20.0.0`. The Node 24 pin was originally there for `util.parseEnv`, which envapt no longer uses now that the internal `.env` parser ships in `src/Dotenv.ts`. Node 20 LTS users (the bulk of the production ecosystem) can install envapt cleanly again. `bun >=1.3.0` and `deno >=2.5.0` engine floors are unchanged.
|
|
66
|
+
- 9711554: new **profiles** support. envapt now auto-loads conventional dotenv-flow files based on the active environment: `.env`, `.env.local`, `.env.${env}`, `.env.${env}.local` (most-specific wins, matches Vite). zero config for the common case.
|
|
67
|
+
|
|
68
|
+
new `Envapter.configureProfiles({...})` for non-conventional path mappings per environment. configured paths layer on top of the cascade with higher precedence; pass `useDefaults: false` to skip the cascade entirely.
|
|
69
|
+
|
|
70
|
+
new `Envapter.resetProfiles()` clears any profile / envPaths configuration back to the cascade default. useful in tests.
|
|
71
|
+
|
|
72
|
+
existing `Envapter.envPaths = '...'` still works as the lowest-level override and takes absolute precedence when explicitly set.
|
|
73
|
+
|
|
74
|
+
- 9711554: Add Standard Schema v1 adapter (zod, valibot, arktype, hand-rolled).
|
|
75
|
+
- New `schema:` option on `@Envapt`. Synchronous schemas only.
|
|
76
|
+
- New `Envapter.parse(key, schema, fallback?)` static + instance methods.
|
|
77
|
+
- New `StandardSchemaV1` interface inlined verbatim from <https://standardschema.dev>; `InferSchemaInput<S>` / `InferSchemaOutput<S>` helpers exported from the package root. Zero runtime peer dependencies.
|
|
78
|
+
- New error codes: `SchemaValidationFailed (208)` populates `err.issues` with the schema's `~standard.validate` issue array; `SchemaThrew (209)` chains the underlying throw via `Error.cause`.
|
|
79
|
+
- Schema slot is mutually exclusive with `converter`: combining them fails to match any overload at compile time, and the runtime Validator throws `InvalidUserDefinedConfig` for dynamic objects that bypass the types.
|
|
80
|
+
- Async-validating schemas resolve the type slot to the `SchemaMustBeSync` brand; the Parser also throws if a Promise leaks past the type check.
|
|
81
|
+
- Missing env + fallback returns the fallback as-is without re-validating it through the schema.
|
|
82
|
+
|
|
83
|
+
- 9711554: Add per-type shorthand decorators: `@EnvNum`, `@EnvStr`, `@EnvBool`, `@EnvUrl`, `@EnvTime`.
|
|
84
|
+
|
|
85
|
+
Each is a thin wrapper over `@Envapt` with a fixed converter, so the call site is the key and an optional fallback (`@EnvNum('PORT', 3000)`). The fallback is typed to the converter: `@EnvUrl` takes a `URL`, `@EnvTime` a millisecond number or a time string, the rest their primitive. They accept the ordered-key array form and resolve through the same cache, getter install, and strict-mode path as `@Envapt`. For `required`, a `schema`, an array, or a custom converter, use `@Envapt` with the options object.
|
|
86
|
+
|
|
87
|
+
- 9711554: Add `Envapter.syncProcessEnv` opt-in to mirror dotenv-loaded keys back to `process.env`.
|
|
88
|
+
- New `Envapter.syncProcessEnv = boolean` (default `false`). Symmetric with `Envapter.strict` / `Envapter.debug`.
|
|
89
|
+
- When `true`, after every cache (re)build envapt writes the keys it loaded from `.env` files into the real `process.env`. Only the keys the loader actually wrote into the isolated env are mirrored, so first-wins (`override: false`, default) leaves a pre-existing `process.env` value alone and `envFileOptions.override = true` lets the file value win in both the cache and the mirror.
|
|
90
|
+
- Flipping `false` to `true` after the cache is already populated mirrors the existing tracked delta immediately (no cache refresh). Flipping `true` to `false` is one-way: previously mirrored keys remain in `process.env` until the process exits.
|
|
91
|
+
- Invalid setter values (non-boolean) throw `EnvaptError(InvalidUserDefinedConfig)`.
|
|
92
|
+
- Verbose debug emits per-key `mirrored KEY to process.env` lines plus a summary `mirrored N keys to process.env` after each mirror.
|
|
93
|
+
|
|
94
|
+
- 9711554: `Converters.Time` fallbacks now accept a time-string in addition to a number: `fallback: '10s'` is the same as `fallback: 10000`. also adds `d` (days) and `w` (weeks) to the supported units. `TimeFallback` is exported if you want to type the fallback yourself.
|
|
95
|
+
|
|
96
|
+
malformed time-string fallbacks (like `'1.5h'` or `'1500'`, where the runtime expects an integer with an explicit unit) now throw `EnvaptErrorCodes.MalformedTimeFallback` instead of the generic `FallbackConverterTypeMismatch`. number fallbacks keep working the same way.
|
|
97
|
+
|
|
98
|
+
### Patch Changes
|
|
99
|
+
|
|
100
|
+
- 9711554: Add cross-runtime integration test layer under `packages/envapt/tests/integration/`.
|
|
101
|
+
- Hand-rolled `node:assert`-based smoke (6 portable suites + 1 Deno-only suite, ~30 assertions): basic get, every built-in converter, fallbacks, missing-file recovery, the `@Envapt` decorator's runtime install path, the v5 features (strict, debug, syncProcessEnv, require), and `@Envapt` syntax compiled by the host runtime's TS transpiler.
|
|
102
|
+
- Runs identically under Node, Bun, and Deno; consumes only the built `dist/index.mjs`.
|
|
103
|
+
- New `test:integration` package script for local Node runs.
|
|
104
|
+
- New GitHub Actions workflow `cross-runtime.yml`: build once, fanout across Node `[20, 22, 24]` on ubuntu plus Node 22 on macos and windows, plus Bun on ubuntu and Deno on ubuntu. Branch protection should gate on the aggregator `cross-runtime ok` job.
|
|
105
|
+
|
|
106
|
+
**Known limitation: Bun direct-`.ts` execution with `@Envapt` syntax.** Bun 1.3.10+ ignores the `experimentalDecorators` tsconfig flag and emits TC39 Stage 3 decorators ([bun#27575](https://github.com/oven-sh/bun/issues/27575)); envapt's `@Envapt` is a legacy TypeScript decorator and the call shapes are incompatible. Bun users who want the decorator API should precompile with `tsc` / `tsdown` / Vite first, then run the compiled output with Bun. The functional API (`Envapter.get`, `getNumber`, etc.) works without any build step under direct-`.ts` execution.
|
|
107
|
+
|
|
108
|
+
No public API change.
|
|
109
|
+
|
|
110
|
+
- 9711554: Instance `get` now narrows its return type on a fallback. A redundant overload made `env.get('KEY', 'fallback')` resolve to `string | undefined` instead of `string`; removing it makes instance `get` match static `get`.
|
|
111
|
+
- 9711554: Minify the published build and mark the package side-effect-free except the `envapt/config` entry. The
|
|
112
|
+
`dist` output is now minified (roughly halving the npm install size), and the `sideEffects` field lets
|
|
113
|
+
bundlers tree-shake the parts of the surface a consumer does not import. No API or behavior change.
|
|
114
|
+
- 9711554: Rewrite the README for v5. The package README is now a short, docs-first landing page: hero, the
|
|
115
|
+
`process.env` to typed-value pitch, install for npm/pnpm/yarn/bun/Deno (JSR), and one quick start each
|
|
116
|
+
for the functional and decorator APIs, an agent-skill install line, with the full reference linked at
|
|
117
|
+
the docs site. Removes the stale v4 surface (the old converter enum, `dotenvConfig`, Node `>=22`, "dotenv bundled").
|
|
118
|
+
|
|
119
|
+
Also refresh the npm `description` and `keywords` for registry and search discoverability (adds
|
|
120
|
+
`typescript`, `type-safe`, `deno`, `bun`, `zod`, `valibot`, `arktype`, `validation`, `decorator`,
|
|
121
|
+
`cross-runtime`, and related terms), and fix the `@Envapt` url-converter `@example` to pass a `URL`
|
|
122
|
+
instance for the fallback instead of a string (the previous example would throw at runtime, since the
|
|
123
|
+
url converter validates the fallback as `instanceof URL`).
|
|
124
|
+
|
|
3
125
|
## 4.1.1
|
|
4
126
|
|
|
5
127
|
### Patch Changes
|