@envilder/sdk

中文文档
1.2.0发布于 2026/11/09MITTypeScriptES Module构建来源已验证近 30 天下载 3049

Load secrets from AWS SSM Parameter Store or Azure Key Vault directly into your Node.js process — no .env files needed.

原始使用文档
文档目录20 节
  1. Prerequisites
  2. Install
  3. Quick Start
  4. One-liner: resolve + inject
  5. Resolve without injecting
  6. Azure Key Vault
  7. Fluent builder (with overrides)
  8. Environment-based loading
  9. Secret validation
  10. Map file contract validation
  11. Advanced usage
  12. Custom provider in the fluent builder
  13. API Reference
  14. Static facade ( Envilder )
  15. Fluent builder (via fromMapFile() )
  16. Validation
  17. Map File Format
  18. Keys and values
  19. Examples
  20. Links

Envilder Node.js SDK

Coverage Report npm version MIT License

Securely load environment variables from AWS SSM Parameter Store or Azure Key Vault directly into your Node.js application. Zero vendor lock-in: secrets stay in your cloud.

Part of the Envilder project.

Prerequisites

  • Node.js 22.12+
  • AWS provider: AWS credentials configured (CLI, environment variables, or IAM role)
  • Azure provider: Azure credentials via az login, managed identity, or environment variables

Install

npm install @envilder/sdk

Quick Start

One-liner: resolve + inject

import { Envilder } from '@envilder/sdk';

// Resolve secrets and inject into process.env
await Envilder.load('envilder.json');

console.log('DB_PASSWORD loaded:', !!process.env.DB_PASSWORD);

Resolve without injecting

import { Envilder } from '@envilder/sdk';

const secrets = await Envilder.resolveFile('envilder.json');
console.log(secrets.get('DB_PASSWORD')); // avoid logging secrets in production

Azure Key Vault

Set the provider in the map file's $config; values are Key Vault secret names:

{
  "$schema": "https://envilder.com/schema/map-file.v1.json",
  "$config": {
    "provider": "azure",
    "vaultUrl": "https://my-vault.vault.azure.net"
  },
  "DB_PASSWORD": "myapp-prod-db-password"
}

Values are sent to Key Vault as written, except that slashes become hyphens: a path-style value such as /myapp/prod/db-password is read as myapp-prod-db-password, the same name the CLI pushes it under.

The code is the same as for AWS. Credentials are resolved with DefaultAzureCredential (az login, managed identity, or environment variables):

import { Envilder } from '@envilder/sdk';

await Envilder.load('envilder.json');

console.log('DB_PASSWORD loaded:', !!process.env.DB_PASSWORD);

Fluent builder (with overrides)

Override the map file's $config at runtime: useful for switching providers, profiles, or vault URLs per environment:

import { Envilder, SecretProviderType } from '@envilder/sdk';

// Override provider + vault URL
const secrets = await Envilder.fromMapFile('envilder.json')
  .withProvider(SecretProviderType.Azure)
  .withVaultUrl('https://my-vault.vault.azure.net')
  .resolve();

// Override AWS profile and inject
await Envilder.fromMapFile('envilder.json')
  .withProfile('staging')
  .inject();

Environment-based loading

Route secret loading based on your current environment. Each environment maps to its own secrets file (or null to skip loading):

import { Envilder } from '@envilder/sdk';

const env = process.env.APP_ENV ?? 'development';

// Resolve + inject into process.env
await Envilder.load(env, {
  production: 'prod-secrets.json',
  development: 'dev-secrets.json',
  test: null, // no secrets loaded
});

Resolve without injecting:

const secrets = await Envilder.resolveFile(env, {
  production: 'prod-secrets.json',
  development: 'dev-secrets.json',
  test: null,
});

Behavior:

  • If the environment maps to a file path, secrets are loaded from that file.
  • If the environment maps to null or is not in the mapping, an empty Map is returned silently.
  • Empty or whitespace-only environment names throw Error.

Secret validation

Opt-in validation ensures all resolved secrets have non-empty values:

import { Envilder, validateSecrets } from '@envilder/sdk';

const secrets = await Envilder.resolveFile('envilder.json');
validateSecrets(secrets); // throws SecretValidationError if any value is empty

validateSecrets() checks that:

  • The map is not empty (throws SecretValidationError with empty missingKeys)
  • Every value is non-empty (throws SecretValidationError listing the failing keys)
  • Passes silently when all values are present
import { SecretValidationError, validateSecrets } from '@envilder/sdk';

try {
  validateSecrets(secrets);
} catch (err) {
  if (err instanceof SecretValidationError) {
    console.log(`Missing: ${err.missingKeys.join(', ')}`);
  }
}

Map file contract validation

Check, before loading anything, that the map file is valid and that every declared secret exists with the current credentials. No secret value is used or returned. This is the same check as envilder validate in the CLI.

import { Envilder } from '@envilder/sdk';

const result = await Envilder.fromMapFile('envilder.json').validateContract();

if (!result.isValid) {
  for (const error of result.mapFileErrors) {
    console.error(`${error.key}: ${error.message}`);
  }
  for (const key of result.keys.filter((k) => k.status !== 'exists')) {
    console.error(`${key.variable} (${key.provider} ${key.path}): ${key.status}`);
  }
}

validateContract() never throws for expected failures; they are reported in the result:

  • mapFileErrors: the map file does not match the published schema or its provider configuration cannot work (for example vaultUrl with AWS). When there are any, no provider is called and keys is empty.
  • keys: one entry per variable with its path, provider and status: exists, missing, access_denied (the identity cannot check the secret, never reported as missing), authentication_failed or provider_error. reason explains the last three when the provider gave one.

To fail a load when the contract does not hold, opt in on the builder. The check runs once before resolving and throws ContractValidationError, whose message names the failing keys and paths (never their values) and whose result holds the full outcome:

await Envilder.fromMapFile('envilder.json')
  .withContractValidation()
  .inject(); // throws ContractValidationError if a key is missing

Without withContractValidation(), a load makes no extra provider call and needs no extra permission. The check needs ssm:GetParameters on AWS (it uses GetParameters in batches of ten with WithDecryption: false; plain String values can still come back in the response and are discarded, and with kms:Decrypt the same permission reads decrypted values, so scope it like ssm:GetParameter) and, on Azure Key Vault, the List secret permission (access policies) or Microsoft.KeyVault/vaults/secrets/readMetadata/action (Azure RBAC, included in Key Vault Secrets User), because it lists secret metadata instead of reading values.

Contract validation and validateSecrets() answer different questions: contract validation checks that the map file is valid and each declared secret exists, before resolving; validateSecrets() checks that the values already resolved are not empty.

Advanced usage

Implement the ISecretProvider interface to plug in a custom backend (e.g., HashiCorp Vault, GCP Secret Manager):

import {
  EnvilderClient,
  MapFileParser,
  type ISecretProvider,
} from '@envilder/sdk';
import { readFileSync } from 'node:fs';

class MyCustomProvider implements ISecretProvider {
  async getSecrets(names: string[]): Promise<Map<string, string>> {
    // fetch from your custom backend
    return new Map();
  }
}

const json = readFileSync('envilder.json', 'utf-8');
const mapFile = new MapFileParser().parse(json);

const provider = new MyCustomProvider();
const client = new EnvilderClient(provider);
const secrets = await client.resolveSecrets(mapFile);
EnvilderClient.injectIntoEnvironment(secrets);

Custom provider in the fluent builder

withSecretProvider() hands the builder your own provider instance instead of the one it would build from $config. The map file is still validated as usual, so this is also the way to test your startup code against an in-memory fake, with no cloud account, emulator or environment variables:

import {
  Envilder,
  type ISecretExistenceChecker,
  type ISecretProvider,
} from '@envilder/sdk';

const fakeSecrets = new Map([['/app/db-url', 'postgres://localhost/test']]);

class InMemoryProvider implements ISecretProvider, ISecretExistenceChecker {
  async getSecrets(names: string[]): Promise<Map<string, string>> {
    return new Map(
      names.flatMap((name) => {
        const value = fakeSecrets.get(name);
        return value === undefined ? [] : [[name, value] as const];
      }),
    );
  }

  async checkSecretsExist(names: readonly string[]) {
    return new Map(
      names.map((name) => [
        name,
        { status: fakeSecrets.has(name) ? 'exists' : 'missing' } as const,
      ]),
    );
  }
}

await Envilder.fromMapFile('envilder.json')
  .withSecretProvider(new InMemoryProvider())
  .withContractValidation()
  .inject();

To take part in contract validation, the provider also implements ISecretExistenceChecker. A provider that only implements ISecretProvider still resolves secrets, but validateContract() reports every key as provider_error, so withContractValidation() fails the load. The provider field of each key keeps the configured type (withProvider(), then $config.provider, then aws).

For a complete, runnable walkthrough, see typescript-custom-provider in envilder-examples: a custom provider over a local AES-256-GCM encrypted file, with tests for loading, failing at startup on a missing secret, and validating the contract without decrypting anything.

API Reference

Static facade (Envilder)

MethodDescription
load(path)Resolve secrets and inject into process.env
resolveFile(path)Resolve secrets, return as Map<string, string>
load(env, mapping)Environment-based resolve + inject
resolveFile(env, mapping)Environment-based resolve
fromMapFile(path)Returns fluent builder for configuration

Fluent builder (via fromMapFile())

MethodDescription
withProvider(type)Override secret provider (AWS/Azure)
withProfile(name)Override AWS named profile
withVaultUrl(url)Override Azure Key Vault URL
withSecretProvider(provider)Use your own ISecretProvider instance instead of building one from $config
withContractValidation()Check the map file contract once before resolving; fail with ContractValidationError
validateContract()Check the map file contract and return a ContractValidationResult, without loading
resolve()Resolve secrets, return as Map
inject()Resolve + inject into process.env

Validation

FunctionDescription
validateSecrets(map)Throws SecretValidationError if any value is empty or map is empty

Map File Format

{
  "$schema": "https://envilder.com/schema/map-file.v1.json",
  "$config": {
    "provider": "aws",
    "profile": "my-profile"
  },
  "DB_PASSWORD": "/app/prod/db-password",
  "API_KEY": "/app/prod/api-key"
}

Supported providers: aws (default), azure.

For Azure, add vaultUrl:

{
  "$schema": "https://envilder.com/schema/map-file.v1.json",
  "$config": {
    "provider": "azure",
    "vaultUrl": "https://my-vault.vault.azure.net"
  },
  "DB_PASSWORD": "myapp-prod-db-password",
  "API_KEY": "myapp-prod-api-key"
}

Keys and values

Keys follow the same rule as the CLI and the GitHub Action, so a key accepted by one is accepted by all:

  • Keys may only contain letters, digits, _, ., - and / (^[A-Za-z0-9_./-]+$); __proto__ is also rejected. MapFileParser.parse throws Error for any other key, before any secret is fetched. / is allowed for hierarchical names (Database/Password) and returned as-is.
  • Values are the secret identifiers in the provider (SSM parameter name or Key Vault secret name) and must be JSON strings.
  • Secret contents are returned exactly as the provider stores them. resolveFile / resolve keep them in memory; load / inject write them to the process environment, where the operating system cannot store NUL (U+0000) and Windows limits a variable to 32,767 characters.

See Keys and Values: What Is Accepted for the full reference and the reasoning behind the rules.

See the root README for the full map file reference.

Examples

Runnable projects in envilder-examples resolve a map file against AWS SSM and Azure Key Vault (emulated with LocalStack for AWS and LocalStack for Azure) and pass the values to containers, with no .env file:

版本与发布记录

@envilder/sdk 共发布 11 个版本,首次发布于 2026/04/30;过去 12 个月发布了 11 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.2.0latest2026/11/095 天前
1.1.02026/11/0410 天前
1.0.02026/10/2817 天前
0.4.22026/10/2817 天前
0.4.12026/09/271 个月前
0.4.02026/07/114 个月前

关于 @envilder/sdk 的常见问题

@envilder/sdk 是什么?

Load secrets from AWS SSM Parameter Store or Azure Key Vault directly into your Node.js process — no .env files needed.

如何安装 @envilder/sdk?

在项目目录运行 npm install @envilder/sdk,或使用 pnpm add / yarn add / bun add。

@envilder/sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@envilder/sdk 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@envilder/sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.12.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@envilder/sdk 可以商用吗?

@envilder/sdk 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@envilder/sdk 的下载量有多少?

根据 npm 官方下载统计,@envilder/sdk 在 2026/10/14 – 2026/11/12 这 30 天内被下载 3,049 次,日均约 102 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@envilder/sdk 还在维护吗?

最新版本 1.2.0 发布于 2026/11/09(5 天前);至今共发布 11 个版本,其中过去 12 个月发布了 11 个;首次发布于 2026/04/30。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。