@super-repo/envx 0.4.0 → 0.4.1-b.2

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 (106) hide show
  1. package/README.md +2 -2
  2. package/dist/auto.js +1 -1
  3. package/dist/chunks/auto-preload-CrSuZDg1.js +75 -0
  4. package/dist/chunks/auto-preload-CrSuZDg1.js.map +1 -0
  5. package/dist/chunks/aws-DgcXfw-Y.js +54 -0
  6. package/dist/chunks/aws-DgcXfw-Y.js.map +1 -0
  7. package/dist/chunks/azure-Cmh5-dPn.js +62 -0
  8. package/dist/chunks/azure-Cmh5-dPn.js.map +1 -0
  9. package/dist/chunks/{commands-KUyDszno.js → commands-Br0Z7uUF.js} +2 -2
  10. package/dist/chunks/commands-Br0Z7uUF.js.map +1 -0
  11. package/dist/chunks/doppler-BkQsajIp.js +50 -0
  12. package/dist/chunks/doppler-BkQsajIp.js.map +1 -0
  13. package/dist/chunks/gcp-Dq7QncPS.js +53 -0
  14. package/dist/chunks/gcp-Dq7QncPS.js.map +1 -0
  15. package/dist/chunks/infisical-CO073rdx.js +57 -0
  16. package/dist/chunks/infisical-CO073rdx.js.map +1 -0
  17. package/dist/chunks/{src-Ln2uXfYC.js → libs-CqVa6LY9.js} +0 -0
  18. package/dist/chunks/libs-CqVa6LY9.js.map +1 -0
  19. package/dist/chunks/op-CG9UWJIj.js +76 -0
  20. package/dist/chunks/op-CG9UWJIj.js.map +1 -0
  21. package/dist/chunks/runtime-BIEf_Dgo.js +102 -0
  22. package/dist/chunks/runtime-BIEf_Dgo.js.map +1 -0
  23. package/dist/chunks/{src-BM4EdT3z.js → src-ke3h417V.js} +2 -2
  24. package/dist/chunks/src-ke3h417V.js.map +1 -0
  25. package/dist/chunks/types-COrFYR0z.js +62 -0
  26. package/dist/chunks/types-COrFYR0z.js.map +1 -0
  27. package/dist/chunks/vault-BWdO9DFO.js +54 -0
  28. package/dist/chunks/vault-BWdO9DFO.js.map +1 -0
  29. package/dist/cli.js +1 -1
  30. package/dist/commands/index.js +1 -1
  31. package/dist/index.d.ts +3 -3
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +2 -2
  34. package/dist/libs/audit.d.ts +62 -0
  35. package/dist/libs/audit.d.ts.map +1 -0
  36. package/dist/libs/config.d.ts +185 -0
  37. package/dist/libs/config.d.ts.map +1 -0
  38. package/dist/libs/crypto.d.ts +34 -0
  39. package/dist/libs/crypto.d.ts.map +1 -0
  40. package/dist/libs/decrypt.d.ts +10 -0
  41. package/dist/libs/decrypt.d.ts.map +1 -0
  42. package/dist/libs/encrypt.d.ts +21 -0
  43. package/dist/libs/encrypt.d.ts.map +1 -0
  44. package/dist/libs/env.d.ts +178 -0
  45. package/dist/libs/env.d.ts.map +1 -0
  46. package/dist/libs/expand.d.ts +51 -0
  47. package/dist/libs/expand.d.ts.map +1 -0
  48. package/dist/libs/index.d.ts +22 -0
  49. package/dist/libs/index.d.ts.map +1 -0
  50. package/dist/libs/index.js +2 -0
  51. package/dist/libs/keys.d.ts +92 -0
  52. package/dist/libs/keys.d.ts.map +1 -0
  53. package/dist/libs/match.d.ts +7 -0
  54. package/dist/libs/match.d.ts.map +1 -0
  55. package/dist/libs/parser.d.ts +33 -0
  56. package/dist/libs/parser.d.ts.map +1 -0
  57. package/dist/libs/rotate.d.ts +24 -0
  58. package/dist/libs/rotate.d.ts.map +1 -0
  59. package/dist/libs/types.d.ts +42 -0
  60. package/dist/libs/types.d.ts.map +1 -0
  61. package/dist/plugins/auto-preload.d.ts +50 -0
  62. package/dist/plugins/auto-preload.d.ts.map +1 -0
  63. package/dist/plugins/auto-preload.js +2 -0
  64. package/dist/plugins/aws.d.ts +52 -0
  65. package/dist/plugins/aws.d.ts.map +1 -0
  66. package/dist/plugins/aws.js +2 -0
  67. package/dist/plugins/azure.d.ts +46 -0
  68. package/dist/plugins/azure.d.ts.map +1 -0
  69. package/dist/plugins/azure.js +2 -0
  70. package/dist/plugins/doppler.d.ts +36 -0
  71. package/dist/plugins/doppler.d.ts.map +1 -0
  72. package/dist/plugins/doppler.js +2 -0
  73. package/dist/plugins/gcp.d.ts +48 -0
  74. package/dist/plugins/gcp.d.ts.map +1 -0
  75. package/dist/plugins/gcp.js +2 -0
  76. package/dist/plugins/index.d.ts +11 -0
  77. package/dist/plugins/index.d.ts.map +1 -0
  78. package/dist/plugins/index.js +11 -0
  79. package/dist/plugins/infisical.d.ts +51 -0
  80. package/dist/plugins/infisical.d.ts.map +1 -0
  81. package/dist/plugins/infisical.js +2 -0
  82. package/dist/plugins/op.d.ts +52 -0
  83. package/dist/plugins/op.d.ts.map +1 -0
  84. package/dist/plugins/op.js +2 -0
  85. package/dist/plugins/runtime.d.ts +95 -0
  86. package/dist/plugins/runtime.d.ts.map +1 -0
  87. package/dist/plugins/runtime.js +2 -0
  88. package/dist/plugins/types.d.ts +54 -0
  89. package/dist/plugins/types.d.ts.map +1 -0
  90. package/dist/plugins/vault.d.ts +47 -0
  91. package/dist/plugins/vault.d.ts.map +1 -0
  92. package/dist/plugins/vault.js +2 -0
  93. package/docs/plugins/custom-providers.md +26 -0
  94. package/docs/plugins/library-api.md +52 -0
  95. package/docs/plugins/overview.md +96 -0
  96. package/docs/plugins/providers.md +149 -0
  97. package/docs/plugins/recipes.md +77 -0
  98. package/docs/plugins/runtime.md +88 -0
  99. package/docs/security-models.md +3 -3
  100. package/package.json +51 -11
  101. package/dist/bin/dotenvx.d.ts +0 -1
  102. package/dist/bin/dotenvx.d.ts.map +0 -1
  103. package/dist/bin/dotenvx.js +0 -2
  104. package/dist/chunks/commands-KUyDszno.js.map +0 -1
  105. package/dist/chunks/src-BM4EdT3z.js.map +0 -1
  106. package/dist/chunks/src-Ln2uXfYC.js.map +0 -1
@@ -0,0 +1,96 @@
1
+ # @super-repo/envx/plugins
2
+
3
+ > Secret-provider plugins for envx — `${aws-secrets:my-db}` and `${vault:prod/api}` style refs that resolve at load time from real backends.
4
+
5
+ [![NPM](https://nodei.co/npm/@super-repo/envx/plugins.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/@super-repo/envx/plugins)
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@super-repo/envx/plugins.svg)](https://www.npmjs.com/package/@super-repo/envx/plugins)
8
+ [![npm downloads](https://img.shields.io/npm/dm/@super-repo/envx/plugins.svg)](https://www.npmjs.com/package/@super-repo/envx/plugins)
9
+ [![license](https://img.shields.io/npm/l/@super-repo/envx/plugins.svg)](./LICENSE)
10
+
11
+ `.env*` files are great until the secrets in them shouldn't sit on disk. envx-plugins lets you write `${aws-secrets:prod/db}` (or vault, 1Password, Doppler, …) directly in `.env*` and have envx resolve those refs against the real backend at load time. Each plugin returns a `SecretProvider` you wire into [envx's](https://www.npmjs.com/package/@super-repo/envx) `resolvers:` config.
12
+
13
+ The package itself has zero runtime SDK dependencies. Each plugin lazy-loads its provider's SDK on first use, so you only install the SDKs you actually reference.
14
+
15
+ ## Getting started
16
+
17
+ ```sh
18
+ pnpm add @super-repo/envx/plugins
19
+ ```
20
+
21
+ ```ts
22
+ // bootstrap.ts
23
+ import envx from "@super-repo/envx";
24
+ import { awsSecrets, autoPreload, asResolvers } from "@super-repo/envx/plugins";
25
+
26
+ const aws = awsSecrets({ region: "us-east-1" });
27
+
28
+ await autoPreload([aws], { envFiles: [".env"] });
29
+
30
+ envx({
31
+ resolvers: asResolvers([aws]),
32
+ });
33
+ ```
34
+
35
+ ```
36
+ # .env
37
+ DATABASE_URL=${aws-secrets:prod/db}
38
+ API_KEY=${aws-secrets:prod/api-key}
39
+ ```
40
+
41
+ For the all-seven-providers wiring, per-provider auth, edge-runtime usage, and custom backends, see [Docs](#docs).
42
+
43
+ ## Features
44
+
45
+ | provider | edge-runtime | reference syntax |
46
+ | ---------------------- | :----------: | ------------------------------------------------- |
47
+ | **AWS Secrets Manager** | ⚠ | `${aws-secrets:<name>}` (`@v3` for version pin) |
48
+ | **GCP Secret Manager** | ⚠ | `${gcp-secrets:<name>}` (`@3` for version pin) |
49
+ | **Azure Key Vault** | ⚠ | `${azure-keyvault:<name>}` (`@<version>` for pin) |
50
+ | **HashiCorp Vault** | ✓ | `${vault:<path>}` (`#<field>` for JSON field) |
51
+ | **1Password (CLI)** | ✗ | `${op:op://vault/item/field}` |
52
+ | **1Password (SDK)** | depends | `${op:op://vault/item/field}` |
53
+ | **Doppler** | ✓ | `${doppler:<NAME>}` |
54
+ | **Infisical** | ✓ | `${infisical:<NAME>}` |
55
+
56
+ ✓ = native `fetch`, runs in Workers / Edge / Deno. ⚠ = needs Node-compatible runtime (Lambda, Cloud Run, Node). ✗ = spawns a child process. Full table with caveats: [docs/runtime.md](./docs/runtime.md#edge-runtime-compatibility-per-provider).
57
+
58
+ Beyond the per-provider plugins:
59
+
60
+ - **`autoPreload`** — scans your `envFiles` first, only invokes providers that actually appear, and runs them in parallel.
61
+ - **`asResolvers`** — turns a provider list into the `{ name → resolve }` map envx expects.
62
+ - **`buildProvider`** — wrap any async `(id) => Promise<string>` fetcher into a first-class `SecretProvider` for in-house backends.
63
+ - **`createSecretRuntime`** (`/runtime` subpath) — V8-isolate-safe, TTL-cached, single-flight async fetch for edge / serverless.
64
+
65
+ ## Comparison
66
+
67
+ | feature | `@super-repo/envx/plugins` | `dotenv-vault` | direct vendor SDKs |
68
+ | -------------------------------------- | :------------------------: | :----------------: | :----------------: |
69
+ | `${ref}` interpolation in `.env*` | ✓ | ✗ | ✗ |
70
+ | Pluggable, multi-vendor in one config | ✓ | ✗ (one backend) | n/a |
71
+ | Lazy SDK install per provider | ✓ | n/a | ✗ |
72
+ | Edge-runtime entry (V8-isolate-safe) | ✓ | ✗ | varies |
73
+ | Works without leaving envx's pipeline | ✓ | replaces dotenv | replaces dotenv |
74
+
75
+ `dotenv-vault` and the official Doppler / Infisical CLIs each take over the entire env story. envx-plugins keeps envx as the loader and adds vendor-backed `${ref}` resolution as a layer on top — so one repo can mix AWS for DB credentials, Vault for service tokens, and 1Password for developer secrets without three different bootstrap shapes.
76
+
77
+ ## Docs
78
+
79
+ Deep references and worked examples live alongside this package in [./docs/](./docs/):
80
+
81
+ - **[providers.md](./docs/providers.md)** — per-provider auth, options, and `${ref}` syntax for AWS, GCP, Azure, Vault, 1Password (CLI + SDK), Doppler, Infisical.
82
+ - **[recipes.md](./docs/recipes.md)** — the all-seven-providers bootstrap, plus the SDK install matrix.
83
+ - **[runtime.md](./docs/runtime.md)** — `createSecretRuntime` for edge / serverless: TTL caching, single-flight, failure modes, edge-compat table.
84
+ - **[custom-providers.md](./docs/custom-providers.md)** — wrap any backend with `buildProvider`.
85
+ - **[library-api.md](./docs/library-api.md)** — `SecretProvider` shape, `autoPreload`, `asResolvers`, `buildProvider`, `MissingSdkError`, subpath imports.
86
+
87
+ ## References
88
+
89
+ - [`@super-repo/envx`](../core) — the loader these plugins plug into. envx-plugins has no purpose without it; the two are designed to be used together.
90
+ - [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/) · [GCP Secret Manager](https://cloud.google.com/secret-manager/docs) · [Azure Key Vault](https://learn.microsoft.com/azure/key-vault/) · [HashiCorp Vault KV](https://developer.hashicorp.com/vault/docs/secrets/kv)
91
+ - [1Password Service Accounts](https://developer.1password.com/docs/service-accounts) · [Doppler API](https://docs.doppler.com/reference) · [Infisical API](https://infisical.com/docs/api-reference/overview/introduction)
92
+ - [Project README](../../../README.md)
93
+
94
+ ## License
95
+
96
+ MIT © Super-Repo contributors. See [LICENSE](./LICENSE).
@@ -0,0 +1,149 @@
1
+ # Per-provider setup
2
+
3
+ Each plugin has its own auth surface and `${ref}` syntax. All return the same `SecretProvider` shape, so they compose together inside one `asResolvers([...])` / `autoPreload([...])` call (see [Quick start](../README.md#getting-started) and [recipes.md](./recipes.md)).
4
+
5
+ ## AWS Secrets Manager
6
+
7
+ ```ts
8
+ import { awsSecrets } from "@super-repo/envx/plugins/aws";
9
+
10
+ const aws = awsSecrets({ region: "us-east-1" });
11
+ await aws.preload(["prod/db", "prod/api-key"]);
12
+ ```
13
+
14
+ ```
15
+ DATABASE_URL=${aws-secrets:prod/db}
16
+ API_KEY=${aws-secrets:prod/api-key}
17
+ ```
18
+
19
+ Multiple regions? Give each its own provider name and reference accordingly:
20
+
21
+ ```ts
22
+ const awsUs = awsSecrets({ region: "us-east-1", name: "aws-us" });
23
+ const awsEu = awsSecrets({ region: "eu-west-1", name: "aws-eu" });
24
+ ```
25
+
26
+ ```
27
+ DB_US=${aws-us:prod/db}
28
+ DB_EU=${aws-eu:prod/db}
29
+ ```
30
+
31
+ ## GCP Secret Manager
32
+
33
+ ```ts
34
+ import { gcpSecrets } from "@super-repo/envx/plugins/gcp";
35
+
36
+ const gcp = gcpSecrets({ projectId: "acme-prod" });
37
+ await gcp.preload(["prod-db", "prod-api"]);
38
+ ```
39
+
40
+ ```
41
+ DB_URL=${gcp-secrets:prod-db}
42
+ API_KEY=${gcp-secrets:prod-api@3} # pin to version 3
43
+ ```
44
+
45
+ ## Azure Key Vault
46
+
47
+ ```ts
48
+ import { azureKeyVault } from "@super-repo/envx/plugins/azure";
49
+
50
+ const az = azureKeyVault({
51
+ vaultUrl: "https://my-vault.vault.azure.net",
52
+ });
53
+ await az.preload(["prod-db", "prod-jwt-signing"]);
54
+ ```
55
+
56
+ ```
57
+ DB_URL=${azure-keyvault:prod-db}
58
+ JWT_SECRET=${azure-keyvault:prod-jwt-signing@<version>}
59
+ ```
60
+
61
+ Credentials come from `DefaultAzureCredential` by default (env vars → managed identity → Azure CLI → VS Code, in that order). Pass `credential:` to override.
62
+
63
+ ## HashiCorp Vault (KV v1 / v2)
64
+
65
+ ```ts
66
+ import { hcVault } from "@super-repo/envx/plugins/vault";
67
+
68
+ const vault = hcVault({
69
+ endpoint: process.env.VAULT_ADDR!,
70
+ token: process.env.VAULT_TOKEN!,
71
+ mount: "secret",
72
+ });
73
+ await vault.preload(["prod/db", "prod/api"]);
74
+ ```
75
+
76
+ ```
77
+ DB_URL=${vault:prod/db} # reads `data.value` field by default
78
+ USERNAME=${vault:prod/db#username} # specific JSON field
79
+ ```
80
+
81
+ KV v1? Pass `kvVersion: 1`.
82
+
83
+ ## 1Password — CLI mode (developer machines)
84
+
85
+ If `op` is signed in on your machine, no token / SDK is required:
86
+
87
+ ```ts
88
+ import { onePassword } from "@super-repo/envx/plugins/op";
89
+
90
+ const op = onePassword();
91
+ await op.preload([
92
+ "op://prod/Database/url",
93
+ "op://prod/API/key",
94
+ ]);
95
+ ```
96
+
97
+ ```
98
+ DB_URL=${op:op://prod/Database/url}
99
+ API_KEY=${op:op://prod/API/key}
100
+ ```
101
+
102
+ ## 1Password — SDK mode (CI / containers)
103
+
104
+ Use a service-account token in environments without an interactive `op signin`:
105
+
106
+ ```ts
107
+ const op = onePassword({
108
+ token: process.env.OP_SERVICE_ACCOUNT_TOKEN!,
109
+ });
110
+ ```
111
+
112
+ The plugin lazy-loads `@1password/sdk` only in this mode.
113
+
114
+ ## Doppler
115
+
116
+ ```ts
117
+ import { doppler } from "@super-repo/envx/plugins/doppler";
118
+
119
+ const dop = doppler({ token: process.env.DOPPLER_TOKEN! });
120
+ await dop.preload(["DATABASE_URL", "API_KEY"]);
121
+ ```
122
+
123
+ ```
124
+ DATABASE_URL=${doppler:DATABASE_URL}
125
+ API_KEY=${doppler:API_KEY}
126
+ ```
127
+
128
+ Service tokens scope to one project + config, so you typically don't pass project/config explicitly.
129
+
130
+ ## Infisical
131
+
132
+ ```ts
133
+ import { infisical } from "@super-repo/envx/plugins/infisical";
134
+
135
+ const inf = infisical({
136
+ token: process.env.INFISICAL_TOKEN!,
137
+ projectId: "proj-1",
138
+ environment: "prod",
139
+ secretPath: "/services/api", // optional
140
+ });
141
+ await inf.preload(["DATABASE_URL", "API_KEY"]);
142
+ ```
143
+
144
+ ```
145
+ DATABASE_URL=${infisical:DATABASE_URL}
146
+ API_KEY=${infisical:API_KEY}
147
+ ```
148
+
149
+ Self-hosted? Pass `endpoint: "https://infisical.example.com"`.
@@ -0,0 +1,77 @@
1
+ # Recipes
2
+
3
+ End-to-end worked example wiring all seven providers into one envx bootstrap.
4
+
5
+ ## All 7 providers in one bootstrap
6
+
7
+ ```ts
8
+ // bootstrap.ts
9
+ import envx from "@super-repo/envx";
10
+ import {
11
+ awsSecrets,
12
+ gcpSecrets,
13
+ azureKeyVault,
14
+ hcVault,
15
+ onePassword,
16
+ doppler,
17
+ infisical,
18
+ autoPreload,
19
+ asResolvers,
20
+ } from "@super-repo/envx/plugins";
21
+
22
+ const aws = awsSecrets({ region: "us-east-1" });
23
+ const gcp = gcpSecrets({ projectId: "acme-prod" });
24
+ const azure = azureKeyVault({ vaultUrl: "https://acme.vault.azure.net" });
25
+ const vault = hcVault({
26
+ endpoint: process.env.VAULT_ADDR!,
27
+ token: process.env.VAULT_TOKEN!,
28
+ });
29
+ const op = onePassword({ token: process.env.OP_SERVICE_ACCOUNT_TOKEN });
30
+ const dop = doppler({ token: process.env.DOPPLER_TOKEN! });
31
+ const inf = infisical({
32
+ token: process.env.INFISICAL_TOKEN!,
33
+ projectId: "proj-1",
34
+ environment: "prod",
35
+ });
36
+
37
+ // One call, per-file scan, parallel resolution.
38
+ await autoPreload([aws, gcp, azure, vault, op, dop, inf], {
39
+ envFiles: [".env", "vault/.env.prod"],
40
+ });
41
+
42
+ envx({
43
+ // `asResolvers([...])` builds the { name → resolve } map for you.
44
+ resolvers: asResolvers([aws, gcp, azure, vault, op, dop, inf]),
45
+ });
46
+ ```
47
+
48
+ In your `.env*` files:
49
+
50
+ ```
51
+ DATABASE_URL=${aws-secrets:prod/db}
52
+ CACHE_URL=${gcp-secrets:cache-host}
53
+ JWT_SECRET=${azure-keyvault:prod-jwt-signing@v3}
54
+ ROOT_TOKEN=${vault:prod/admin#token}
55
+ GITHUB_PAT=${op:op://prod/GitHub/personal-access-token}
56
+ SENDGRID_KEY=${doppler:SENDGRID_KEY}
57
+ STRIPE_KEY=${infisical:STRIPE_LIVE_KEY}
58
+ ```
59
+
60
+ Only the providers actually referenced in those files get pre-loaded — `autoPreload` scans the files first and skips providers with zero hits.
61
+
62
+ ## SDK install matrix
63
+
64
+ The plugins package itself has zero runtime SDK dependencies. Each plugin lazy-loads its provider's SDK on first use; install only the SDKs you actually need:
65
+
66
+ | provider | install |
67
+ | ------------------ | --------------------------------------------------------------------------- |
68
+ | AWS Secrets Manager | `pnpm add @aws-sdk/client-secrets-manager` |
69
+ | GCP Secret Manager | `pnpm add @google-cloud/secret-manager` |
70
+ | Azure Key Vault | `pnpm add @azure/keyvault-secrets @azure/identity` |
71
+ | HashiCorp Vault | _(no SDK — uses native `fetch`)_ |
72
+ | 1Password (SDK) | `pnpm add @1password/sdk` |
73
+ | 1Password (CLI) | install `op` via [1Password's docs](https://developer.1password.com/docs/cli) |
74
+ | Doppler | _(no SDK — uses native `fetch`)_ |
75
+ | Infisical | _(no SDK — uses native `fetch`)_ |
76
+
77
+ If a provider's SDK isn't installed when you call its `preload`/`fetch`, the plugin throws `MissingSdkError` with the install command — see [library-api.md](./library-api.md).
@@ -0,0 +1,88 @@
1
+ # Runtime / edge — secrets that never leave the source
2
+
3
+ For the "secrets never touch disk, fetched on demand" model, use `createSecretRuntime` from the `/runtime` subpath. Async-first, TTL-cached, V8-isolate-safe — works in Cloudflare Workers, Vercel Edge, Deno Deploy, AWS Lambda, Bun, Node.
4
+
5
+ ```ts
6
+ // src/secrets.ts — module-level singleton, one instance per worker / process
7
+ import { createSecretRuntime } from "@super-repo/envx/plugins/runtime";
8
+ import { hcVault } from "@super-repo/envx/plugins/vault";
9
+
10
+ export const secrets = createSecretRuntime({
11
+ providers: [
12
+ hcVault({
13
+ endpoint: env.VAULT_ADDR,
14
+ token: env.VAULT_TOKEN,
15
+ }),
16
+ ],
17
+ ttl: 300, // refresh after 5 min
18
+ onFailure: "cache-stale", // serve stale on transient backend failures
19
+ });
20
+ ```
21
+
22
+ ```ts
23
+ // Cloudflare Worker, Vercel Edge, Lambda, Deno Deploy — same handler shape
24
+ import { secrets } from "./secrets";
25
+
26
+ export default async function handler(req: Request): Promise<Response> {
27
+ const dbUrl = await secrets.get("vault:prod/db");
28
+ const apiKey = await secrets.get("vault:prod/api");
29
+ return new Response(JSON.stringify({ dbUrl, apiKey }));
30
+ }
31
+ ```
32
+
33
+ ## Behavior
34
+
35
+ - **Lazy fetch** — first read triggers the network call. Subsequent reads inside the TTL window hit the in-memory cache.
36
+ - **Single-flight** — N concurrent reads of the same ref coalesce to one fetch. Edge functions handling a request burst don't fan out N parallel calls to your secret store.
37
+ - **TTL refresh** — values older than `ttl` seconds are refetched on next read.
38
+ - **Failure modes** — `"throw"` (default), `"cache-stale"` (serve previous value, log warn), `"cache-error"` (cache the failure for `errorTtl` seconds so a flaky backend doesn't get hammered).
39
+ - **No fs / child_process imports** — the runtime entry is V8-isolate-safe.
40
+
41
+ ## API
42
+
43
+ ```ts
44
+ interface SecretRuntime {
45
+ get(ref: string): Promise<string>; // throws on miss / unknown provider / failed fetch
46
+ tryGet(ref: string): Promise<string | undefined>; // never throws
47
+ invalidate(ref: string): Promise<string>; // force-refresh a specific ref
48
+ clear(): void; // drop all cached entries
49
+ readonly stats: () => { cached: number; inflight: number; errors: number };
50
+ }
51
+
52
+ interface SecretRuntimeOptions {
53
+ readonly providers: readonly SecretProvider[];
54
+ readonly ttl?: number; // default 300 (5min). 0 = no cache. Infinity = forever.
55
+ readonly onFailure?: "throw" | "cache-stale" | "cache-error";
56
+ readonly errorTtl?: number; // for "cache-error" mode. default 30
57
+ readonly logger?: { warn(msg: string): void };
58
+ }
59
+ ```
60
+
61
+ ## Edge-runtime compatibility per provider
62
+
63
+ | provider | Cloudflare Workers / Vercel Edge / Deno | Lambda / Cloud Run / Node | reason |
64
+ | --------------------- | --------------------------------------- | ------------------------- | ---------------------------- |
65
+ | `hcVault` | ✓ | ✓ | native `fetch` |
66
+ | `doppler` | ✓ | ✓ | native `fetch` |
67
+ | `infisical` | ✓ | ✓ | native `fetch` |
68
+ | `awsSecrets` | ⚠ | ✓ | Node streams in the SDK |
69
+ | `gcpSecrets` | ⚠ | ✓ | gRPC in the SDK |
70
+ | `azureKeyVault` | ⚠ | ✓ | `@azure/identity` token chain |
71
+ | `onePassword` (CLI) | ✗ | ✓ (with `op` on PATH) | spawns a child process |
72
+ | `onePassword` (SDK) | depends on `@1password/sdk` | ✓ | SDK's own constraints |
73
+ | custom `buildProvider`| depends on what your fetcher does | ✓ | usually fine if you use `fetch` |
74
+
75
+ For maximum portability across edges, prefer Vault / Doppler / Infisical, or write your own provider with `buildProvider` (see [custom-providers.md](./custom-providers.md)):
76
+
77
+ ```ts
78
+ import { buildProvider } from "@super-repo/envx/plugins";
79
+
80
+ const myProvider = buildProvider("internal", async (id) => {
81
+ const r = await fetch(`https://internal.example.com/secrets/${id}`, {
82
+ headers: { Authorization: `Bearer ${env.MY_TOKEN}` },
83
+ });
84
+ return (await r.json()).value;
85
+ });
86
+ ```
87
+
88
+ That single-file plugin works in every JS runtime that has `fetch`.
@@ -48,12 +48,12 @@ envx bake --public-only --out .env.resolved && pnpm vite build
48
48
 
49
49
  ## Runtime fetch — edge / serverless
50
50
 
51
- For the "secrets never leave the source-of-truth" model, use `createSecretRuntime` from `@super-repo/envx-plugins/runtime`. Async-first, TTL caching, no `fs` / `child_process` dependencies — works in Cloudflare Workers, Vercel Edge, Deno Deploy, AWS Lambda, Bun, Node.
51
+ For the "secrets never leave the source-of-truth" model, use `createSecretRuntime` from `@super-repo/envx/plugins/runtime`. Async-first, TTL caching, no `fs` / `child_process` dependencies — works in Cloudflare Workers, Vercel Edge, Deno Deploy, AWS Lambda, Bun, Node.
52
52
 
53
53
  ```ts
54
54
  // src/secrets.ts — module-level singleton, one per worker
55
- import { createSecretRuntime } from "@super-repo/envx-plugins/runtime";
56
- import { hcVault } from "@super-repo/envx-plugins/vault";
55
+ import { createSecretRuntime } from "@super-repo/envx/plugins/runtime";
56
+ import { hcVault } from "@super-repo/envx/plugins/vault";
57
57
 
58
58
  export const secrets = createSecretRuntime({
59
59
  providers: [
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@super-repo/envx",
3
3
  "description": "A global executable to run applications with the ENV variables witin a monorepo loaded by dotenvx",
4
- "version": "0.4.0",
4
+ "version": "0.4.1-b.2",
5
5
  "type": "module",
6
6
  "bin": {
7
- "envx": "./dist/cli.js",
8
- "dotenvx-proxy": "./dist/bin/dotenvx.js"
7
+ "envx": "./dist/cli.js"
9
8
  },
10
9
  "exports": {
11
10
  ".": {
@@ -23,6 +22,50 @@
23
22
  "./commands": {
24
23
  "types": "./dist/commands/index.d.ts",
25
24
  "default": "./dist/commands/index.js"
25
+ },
26
+ "./libs": {
27
+ "types": "./dist/libs/index.d.ts",
28
+ "default": "./dist/libs/index.js"
29
+ },
30
+ "./plugins": {
31
+ "types": "./dist/plugins/index.d.ts",
32
+ "default": "./dist/plugins/index.js"
33
+ },
34
+ "./plugins/aws": {
35
+ "types": "./dist/plugins/aws.d.ts",
36
+ "default": "./dist/plugins/aws.js"
37
+ },
38
+ "./plugins/gcp": {
39
+ "types": "./dist/plugins/gcp.d.ts",
40
+ "default": "./dist/plugins/gcp.js"
41
+ },
42
+ "./plugins/azure": {
43
+ "types": "./dist/plugins/azure.d.ts",
44
+ "default": "./dist/plugins/azure.js"
45
+ },
46
+ "./plugins/vault": {
47
+ "types": "./dist/plugins/vault.d.ts",
48
+ "default": "./dist/plugins/vault.js"
49
+ },
50
+ "./plugins/op": {
51
+ "types": "./dist/plugins/op.d.ts",
52
+ "default": "./dist/plugins/op.js"
53
+ },
54
+ "./plugins/doppler": {
55
+ "types": "./dist/plugins/doppler.d.ts",
56
+ "default": "./dist/plugins/doppler.js"
57
+ },
58
+ "./plugins/infisical": {
59
+ "types": "./dist/plugins/infisical.d.ts",
60
+ "default": "./dist/plugins/infisical.js"
61
+ },
62
+ "./plugins/runtime": {
63
+ "types": "./dist/plugins/runtime.d.ts",
64
+ "default": "./dist/plugins/runtime.js"
65
+ },
66
+ "./plugins/auto-preload": {
67
+ "types": "./dist/plugins/auto-preload.d.ts",
68
+ "default": "./dist/plugins/auto-preload.js"
26
69
  }
27
70
  },
28
71
  "files": [
@@ -46,23 +89,20 @@
46
89
  }
47
90
  },
48
91
  "dependencies": {
49
- "@dotenvx/dotenvx": "^1.49.1",
50
92
  "eciesjs": "^0.4.10",
51
93
  "ignore": "^5.3.2",
52
94
  "yargs": "^17.7.0",
53
- "zod": "^3.25.0"
95
+ "zod": "^4.4.3"
54
96
  },
55
97
  "devDependencies": {
56
- "@types/node": "^22.10.0",
98
+ "@types/node": "^25.8.0",
57
99
  "@types/yargs": "^17.0.33",
58
100
  "tsc-alias": "^1.8.16",
59
- "tsx": "^4.21.0",
101
+ "tsx": "^4.22.0",
60
102
  "typescript": "^6.0.3",
61
103
  "vite": "^8.0.11",
62
104
  "vite-plugin-dts": "^5.0.0",
63
- "vitest": "^4.1.5",
64
- "@super-repo/cli": "0.4.0",
65
- "@super-repo/envx-libs": "0.0.1",
66
- "@super-repo/envx-common": "0.0.1"
105
+ "vitest": "^4.1.6",
106
+ "@super-repo/common": "0.0.1"
67
107
  }
68
108
  }
@@ -1 +0,0 @@
1
- //# sourceMappingURL=dotenvx.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dotenvx.d.ts","sourceRoot":"","sources":["../../src/bin/dotenvx.ts"],"names":[],"mappings":"AAQA,OAAO,kBAAkB,CAAC"}
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import "@dotenvx/dotenvx";