npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@envshed/node

v0.2.0

Published

Official Node.js SDK for Envshed — secrets management for teams

Downloads

150

Readme

@envshed/node

Official Node.js SDK for Envshed — secrets management for teams.

Read, write, and manage your Envshed secrets programmatically from any JavaScript or TypeScript project.

Features

  • Full coverage of the Envshed REST API
  • Zero runtime dependencies — uses native fetch (Node 18+)
  • First-class TypeScript support with complete type definitions
  • Automatic retries with exponential backoff for transient failures
  • Namespaced API methods for clean, discoverable usage
  • Dual ESM and CommonJS output

Installation

# npm
npm install @envshed/node

# pnpm
pnpm add @envshed/node

# yarn
yarn add @envshed/node

Requirements: Node.js 18 or later.

Quick Start

import { EnvshedClient } from "@envshed/node";

const client = new EnvshedClient({
  token: process.env.ENVSHED_TOKEN!,
});

// Fetch all secrets for an environment
const { secrets } = await client.secrets.get({
  org: "my-org",
  project: "my-project",
  env: "production",
});

console.log(secrets.DATABASE_URL);
console.log(secrets.API_KEY);

Authentication

The SDK supports two types of tokens:

  • User API tokens (envshed_...) — created from the Envshed dashboard under Settings > API Tokens. These tokens inherit the permissions of the user who created them.
  • Service tokens (envshed_svc_...) — created for CI/CD and machine-to-machine access. These can be scoped to an organization, project, or environment with read_only or read_write permissions.
// Using a user API token
const client = new EnvshedClient({
  token: "envshed_abc123...",
});

// Using a service token
const client = new EnvshedClient({
  token: "envshed_svc_xyz789...",
});

Client Configuration

EnvshedClientOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | token | string | (required) | API authentication token | | apiUrl | string | "https://app.envshed.com" | Base URL for the Envshed API | | retry | RetryOptions | See below | Retry configuration for transient failures |

RetryOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | maxRetries | number | 3 | Maximum retry attempts. Set to 0 to disable retries. | | initialDelayMs | number | 1000 | Initial delay between retries in milliseconds | | maxDelayMs | number | 10000 | Maximum delay cap in milliseconds | | backoff | "exponential" \| "linear" \| BackoffFunction | "exponential" | Backoff strategy between retries (see Retry Strategy) | | shouldRetry | ShouldRetryFunction | 5xx + network errors | Custom function to decide which errors to retry | | onRetry | OnRetryFunction | undefined | Callback invoked before each retry attempt |

const client = new EnvshedClient({
  token: "envshed_...",
  apiUrl: "https://custom-instance.example.com",
  retry: {
    maxRetries: 5,
    initialDelayMs: 500,
    maxDelayMs: 15000,
  },
});

By default, retries use exponential backoff with jitter. Only 5xx server errors and network failures are retried — 4xx client errors are never retried. See the Retry Strategy section for full customization.


API Reference

All methods are async and return typed promises. The client organizes methods into namespaced sub-APIs.

client.me()

Check the authenticated identity.

const me = await client.me();

if ("email" in me) {
  // User token
  console.log(me.email); // "[email protected]"
} else {
  // Service token
  console.log(me.type);       // "service_token"
  console.log(me.org);        // "my-org" | null
  console.log(me.scope);      // "org" | "project" | "environment"
  console.log(me.permission); // "read" | "read_write"
}

Returns: MeResponse — either { email: string } for user tokens or { type: "service_token", org, scope, permission } for service tokens.


Secrets

The most commonly used API. Read and write environment variables.

client.secrets.get(path)

Retrieve all secrets for an environment. Values are returned decrypted.

const result = await client.secrets.get({
  org: "my-org",
  project: "my-project",
  env: "production",
});

console.log(result.secrets);       // { DATABASE_URL: "postgres://...", API_KEY: "sk_..." }
console.log(result.version);       // 42
console.log(result.placeholders);  // ["PLACEHOLDER_KEY"]
console.log(result.linkedKeys);    // ["SHARED_SECRET"]
console.log(result.decryptErrors); // [] (keys that failed to decrypt)

Parameters:

| Param | Type | Description | |-------|------|-------------| | path.org | string | Organization slug | | path.project | string | Project slug | | path.env | string | Environment slug |

Returns: GetSecretsResponse

| Field | Type | Description | |-------|------|-------------| | secrets | Record<string, string> | Key-value pairs of decrypted secrets | | placeholders | string[] | Keys that are placeholders (no real value) | | version | number | Current environment version number | | linkedKeys | string[] | Keys shared from linked projects (optional) | | decryptErrors | string[] | Keys that failed to decrypt (optional) |

client.secrets.set(path, secrets)

Create or update secrets in an environment. Existing keys are updated; new keys are created.

const result = await client.secrets.set(
  { org: "my-org", project: "my-project", env: "production" },
  {
    DATABASE_URL: "postgres://prod-host/mydb",
    API_KEY: "sk_live_new_key",
    NEW_SECRET: "new_value",
  },
);

console.log(result.ok);      // true
console.log(result.version); // 43

Parameters:

| Param | Type | Description | |-------|------|-------------| | path | EnvPath | Organization, project, and environment slugs | | secrets | Record<string, string> | Key-value pairs to upsert |

Returns: SetSecretsResponse{ ok: true, version: number }


Organizations

client.orgs.list()

List all organizations the authenticated user belongs to.

const { organizations } = await client.orgs.list();

for (const org of organizations) {
  console.log(`${org.name} (${org.slug}) — role: ${org.role}`);
}

Returns: ListOrgsResponse{ organizations: Organization[] }

Each Organization has:

| Field | Type | Description | |-------|------|-------------| | name | string | Organization display name | | slug | string | URL-safe identifier | | role | string | User's role: "owner", "admin", or "member" |

client.orgs.create(data)

Create a new organization.

const { organization } = await client.orgs.create({
  name: "Acme Corp",
  slug: "acme-corp",       // optional — auto-generated from name if omitted
  description: "Main org", // optional
});

console.log(organization.slug); // "acme-corp"

Parameters:

| Param | Type | Required | Description | |-------|------|----------|-------------| | name | string | Yes | Organization display name | | slug | string | No | URL-safe identifier (auto-generated if omitted) | | description | string | No | Description |

Returns: CreateOrgResponse{ organization: { name, slug } }


Projects

client.projects.list(org)

List all projects within an organization.

const { projects } = await client.projects.list("my-org");

for (const project of projects) {
  console.log(`${project.name} (${project.slug})`);
}

Parameters:

| Param | Type | Description | |-------|------|-------------| | org | string | Organization slug |

Returns: ListProjectsResponse{ projects: Project[] }

Each Project has:

| Field | Type | Description | |-------|------|-------------| | id | string | Unique identifier | | name | string | Project display name | | slug | string | URL-safe identifier | | description | string \| null | Description |

client.projects.create(org, data)

Create a new project. Automatically creates three default environments: development, staging, and production.

const { project } = await client.projects.create("my-org", {
  name: "Backend API",
  description: "Main backend service", // optional
});

console.log(project.slug); // "backend-api"

Parameters:

| Param | Type | Required | Description | |-------|------|----------|-------------| | org | string | Yes | Organization slug | | name | string | Yes | Project display name | | description | string | No | Description |

Returns: CreateProjectResponse{ project: { name, slug } }


Environments

client.environments.list(org, project)

List all environments within a project.

const { environments } = await client.environments.list("my-org", "my-project");

for (const env of environments) {
  console.log(`${env.name} (${env.slug})`);
}
// "Development (development)"
// "Staging (staging)"
// "Production (production)"

Parameters:

| Param | Type | Description | |-------|------|-------------| | org | string | Organization slug | | project | string | Project slug |

Returns: ListEnvironmentsResponse{ environments: Environment[] }

Each Environment has:

| Field | Type | Description | |-------|------|-------------| | id | string | Unique identifier | | name | string | Environment display name | | slug | string | URL-safe identifier | | description | string \| null | Description |

client.environments.create(org, project, data)

Create a new environment within a project.

const { environment } = await client.environments.create(
  "my-org",
  "my-project",
  {
    name: "QA",
    description: "Quality assurance testing", // optional
  },
);

console.log(environment.slug); // "qa"

Parameters:

| Param | Type | Required | Description | |-------|------|----------|-------------| | org | string | Yes | Organization slug | | project | string | Yes | Project slug | | name | string | Yes | Environment display name | | description | string | No | Description |

Returns: CreateEnvironmentResponse{ environment: { name, slug } }


Environment Version

Track the current version of an environment. Useful for cache invalidation and polling for changes.

client.version.get(path, etag?)

Get the current version of an environment. Supports HTTP ETag for conditional requests — pass the previous ETag to check if the version has changed without re-fetching secrets.

// First request — get the current version
const versionInfo = await client.version.get({
  org: "my-org",
  project: "my-project",
  env: "production",
});
console.log(versionInfo.version);   // 42
console.log(versionInfo.updatedAt); // "2026-02-25T12:00:00Z"

// Subsequent requests — pass the ETag to check for changes
const etag = `"v${versionInfo.version}"`;
const updated = await client.version.get(
  { org: "my-org", project: "my-project", env: "production" },
  etag,
);

if (updated === null) {
  console.log("No changes since last check");
} else {
  console.log(`New version: ${updated.version}`);
}

Parameters:

| Param | Type | Required | Description | |-------|------|----------|-------------| | path | EnvPath | Yes | Organization, project, and environment slugs | | etag | string | No | ETag from a previous response (e.g., "v42") |

Returns: GetVersionResponse | null

  • Returns { version: number, updatedAt: string } if the version has changed (or no ETag was provided).
  • Returns null if the version has not changed (304 Not Modified).

Secret Versions

View the change history of individual secrets and rollback to previous versions.

client.versions.list(path, secretKey, options?)

List the version history for a specific secret key.

const { versions } = await client.versions.list(
  { org: "my-org", project: "my-project", env: "production" },
  "DATABASE_URL",
  { limit: 10, offset: 0 }, // optional pagination
);

for (const v of versions) {
  console.log(`v${v.version} — ${v.changeType} at ${v.createdAt}`);
}
// "v5 — updated at 2026-02-25T12:00:00Z"
// "v3 — created at 2026-02-20T08:00:00Z"

Parameters:

| Param | Type | Required | Description | |-------|------|----------|-------------| | path | EnvPath | Yes | Organization, project, and environment slugs | | secretKey | string | Yes | The secret key name (e.g., "DATABASE_URL") | | options.limit | number | No | Maximum results to return (default: 50) | | options.offset | number | No | Number of results to skip (default: 0) |

Returns: ListSecretVersionsResponse{ versions: SecretVersion[] }

Each SecretVersion has:

| Field | Type | Description | |-------|------|-------------| | version | number | Version number | | changeType | string | "created", "updated", or "rolled_back" | | changedBy | string \| null | User ID who made the change (null for service tokens) | | comment | string \| null | Optional change comment | | createdAt | string | ISO 8601 timestamp |

client.versions.rollback(path, secretKey, targetVersion)

Rollback a secret to a previous version. This creates a new version with the old value.

const result = await client.versions.rollback(
  { org: "my-org", project: "my-project", env: "production" },
  "DATABASE_URL",
  3, // target version to rollback to
);

console.log(result.ok);         // true
console.log(result.newVersion); // 6 (the newly created version)

Parameters:

| Param | Type | Description | |-------|------|-------------| | path | EnvPath | Organization, project, and environment slugs | | secretKey | string | The secret key name | | targetVersion | number | Version number to rollback to |

Returns: RollbackSecretResponse{ ok: true, newVersion: number }


Snapshots

Capture and restore complete environment state. Snapshots save the current version of every secret so you can restore them all at once.

client.snapshots.list(path)

List all snapshots for an environment.

const { snapshots } = await client.snapshots.list({
  org: "my-org",
  project: "my-project",
  env: "production",
});

for (const snap of snapshots) {
  console.log(`${snap.name ?? "Unnamed"} — ${snap.createdAt}`);
}

Returns: ListSnapshotsResponse{ snapshots: Snapshot[] }

Each Snapshot has:

| Field | Type | Description | |-------|------|-------------| | id | string | Unique identifier | | name | string \| null | Optional snapshot name | | description | string \| null | Optional description | | createdBy | string \| null | User ID who created it (null for service tokens) | | createdAt | string | ISO 8601 timestamp |

client.snapshots.create(path, data?)

Create a snapshot of the current environment state.

const snapshot = await client.snapshots.create(
  { org: "my-org", project: "my-project", env: "production" },
  {
    name: "pre-deploy-v2.5",             // optional
    description: "Before v2.5 release",  // optional
  },
);

console.log(snapshot.id);        // "snap_abc123"
console.log(snapshot.name);      // "pre-deploy-v2.5"
console.log(snapshot.createdAt); // "2026-02-25T12:00:00Z"

Parameters:

| Param | Type | Required | Description | |-------|------|----------|-------------| | path | EnvPath | Yes | Organization, project, and environment slugs | | name | string | No | Snapshot name | | description | string | No | Snapshot description |

Returns: CreateSnapshotResponse{ id, name, createdAt }

client.snapshots.restore(path, snapshotId)

Restore an environment to a previous snapshot state. All secrets are restored to their values at the time the snapshot was taken.

const result = await client.snapshots.restore(
  { org: "my-org", project: "my-project", env: "production" },
  "snap_abc123",
);

console.log(result.ok);            // true
console.log(result.restoredCount); // 15 (number of secrets restored)

Parameters:

| Param | Type | Description | |-------|------|-------------| | path | EnvPath | Organization, project, and environment slugs | | snapshotId | string | ID of the snapshot to restore |

Returns: RestoreSnapshotResponse{ ok: true, restoredCount: number }


Service Tokens

Manage machine-to-machine authentication tokens. These endpoints require organization admin or owner access.

client.serviceTokens.list(org)

List all service tokens for an organization.

const { tokens } = await client.serviceTokens.list("my-org");

for (const token of tokens) {
  console.log(`${token.name} (${token.scope}, ${token.permission})`);
  console.log(`  Active: ${token.is_active}`);
  console.log(`  Last used: ${token.last_used_at ?? "never"}`);
}

Returns: ListServiceTokensResponse{ tokens: ServiceToken[] }

Each ServiceToken has:

| Field | Type | Description | |-------|------|-------------| | id | string | Unique identifier | | name | string | Token display name | | description | string \| null | Description | | token_prefix | string | First characters of the token for identification | | scope | "org" \| "project" \| "environment" | Access scope | | project_id | string \| null | Scoped project (if applicable) | | environment_id | string \| null | Scoped environment (if applicable) | | permission | "read" \| "read_write" | Permission level | | expires_at | string \| null | Expiration date (ISO 8601) or null for no expiration | | last_used_at | string \| null | Last usage timestamp | | is_active | boolean | Whether the token is active | | created_at | string | Creation timestamp | | created_by_email | string | Email of the user who created it | | created_by_name | string \| null | Name of the user who created it |

client.serviceTokens.create(org, data)

Create a new service token. The raw token value is returned only once — store it securely.

const result = await client.serviceTokens.create("my-org", {
  name: "CI/CD Pipeline",
  description: "GitHub Actions deployment token",  // optional
  scope: "environment",                             // "org" | "project" | "environment"
  projectId: "project-uuid",                        // required for "project" or "environment" scope
  environmentId: "env-uuid",                        // required for "environment" scope
  permission: "read_only",                          // "read" | "read_write"
  expiresAt: "2026-12-31T23:59:59Z",               // optional ISO 8601 date
});

console.log(result.token); // "envshed_svc_..." — save this, it won't be shown again
console.log(result.id);    // token ID for future management
console.log(result.name);  // "CI/CD Pipeline"

Parameters:

| Param | Type | Required | Description | |-------|------|----------|-------------| | org | string | Yes | Organization slug | | name | string | Yes | Token display name | | description | string | No | Description | | scope | "org" \| "project" \| "environment" | No | Access scope | | projectId | string | Conditional | Required if scope is "project" or "environment" | | environmentId | string | Conditional | Required if scope is "environment" | | permission | "read" \| "read_write" | No | Permission level | | expiresAt | string | No | Expiration date (ISO 8601) |

Returns: CreateServiceTokenResponse{ token, id, name }

client.serviceTokens.delete(org, tokenId)

Revoke a service token. This action is immediate and irreversible.

const result = await client.serviceTokens.delete("my-org", "token-id-123");
console.log(result.ok); // true

Parameters:

| Param | Type | Description | |-------|------|-------------| | org | string | Organization slug | | tokenId | string | ID of the token to revoke |

Returns: DeleteServiceTokenResponse{ ok: true }


Error Handling

The SDK throws typed errors that you can catch and inspect.

EnvshedError

Thrown when the API returns an HTTP error response (4xx or 5xx).

import { EnvshedClient, EnvshedError } from "@envshed/node";

const client = new EnvshedClient({ token: "envshed_..." });

try {
  await client.secrets.get({
    org: "my-org",
    project: "my-project",
    env: "nonexistent",
  });
} catch (err) {
  if (err instanceof EnvshedError) {
    console.log(err.status);     // 404
    console.log(err.apiMessage); // "Environment not found"
    console.log(err.method);     // "GET"
    console.log(err.path);       // "/secrets/my-org/my-project/nonexistent"

    // Convenience getters
    if (err.isNotFound) {
      console.log("Resource does not exist");
    } else if (err.isUnauthorized) {
      console.log("Invalid or expired token");
    } else if (err.isForbidden) {
      console.log("Insufficient permissions");
    } else if (err.isSubscriptionRequired) {
      console.log("Organization subscription required");
    } else if (err.isRetryable) {
      console.log("Server error — retries were exhausted");
    }
  }
}

Properties:

| Property | Type | Description | |----------|------|-------------| | status | number | HTTP status code | | apiMessage | string | Error message from the API | | method | string | HTTP method (GET, POST, PUT, DELETE) | | path | string | API path that was called | | isUnauthorized | boolean | true if status is 401 | | isForbidden | boolean | true if status is 403 | | isNotFound | boolean | true if status is 404 | | isSubscriptionRequired | boolean | true if status is 402 | | isRetryable | boolean | true if status is 5xx |

EnvshedNetworkError

Thrown when a network-level failure occurs (DNS resolution failure, connection refused, timeout, etc.). These errors are always considered retryable and will be retried according to your retry configuration before being thrown.

import { EnvshedClient, EnvshedNetworkError } from "@envshed/node";

try {
  await client.me();
} catch (err) {
  if (err instanceof EnvshedNetworkError) {
    console.log(err.message);    // "Envshed network error: fetch failed"
    console.log(err.method);     // "GET"
    console.log(err.path);       // "/me"
    console.log(err.cause);      // Original Error object
    console.log(err.isRetryable); // true (always)
  }
}

Properties:

| Property | Type | Description | |----------|------|-------------| | method | string | HTTP method | | path | string | API path that was called | | cause | Error | The original network error | | isRetryable | boolean | Always true |


Retry Strategy

The SDK automatically retries failed requests for transient failures. The retry behavior is fully customizable.

Default behavior

  • 5xx server errors — retried up to maxRetries times
  • Network errors (DNS, connection refused, timeout) — retried up to maxRetries times
  • 4xx client errors — never retried (these are deterministic)

Retries use exponential backoff with jitter:

delay = min(initialDelayMs * 2^(attempt - 1), maxDelayMs) +/- 25% jitter

With default settings (maxRetries: 3, initialDelayMs: 1000, maxDelayMs: 10000), retry delays are approximately:

| Attempt | Base Delay | With Jitter | |---------|-----------|-------------| | 1st retry | 1000ms | 750–1250ms | | 2nd retry | 2000ms | 1500–2500ms | | 3rd retry | 4000ms | 3000–5000ms |

To disable retries entirely:

const client = new EnvshedClient({
  token: "envshed_...",
  retry: { maxRetries: 0 },
});

Backoff strategies

Choose between built-in strategies or provide your own function.

Exponential (default) — delay doubles each attempt:

const client = new EnvshedClient({
  token: "envshed_...",
  retry: {
    backoff: "exponential", // initialDelayMs * 2^(attempt-1)
  },
});

Linear — constant delay between retries:

const client = new EnvshedClient({
  token: "envshed_...",
  retry: {
    backoff: "linear", // initialDelayMs for every attempt
  },
});

Custom function — return the delay in milliseconds (still capped by maxDelayMs):

const client = new EnvshedClient({
  token: "envshed_...",
  retry: {
    initialDelayMs: 100,
    maxDelayMs: 30000,
    backoff: (attempt, initialDelayMs) => {
      // Cubic backoff: 100ms, 800ms, 2700ms, ...
      return initialDelayMs * Math.pow(attempt, 3);
    },
  },
});

The BackoffFunction signature:

type BackoffFunction = (attempt: number, initialDelayMs: number) => number;
  • attempt — 1-based attempt number (1 for the first retry, 2 for the second, etc.)
  • initialDelayMs — the configured initialDelayMs value
  • Return value is capped by maxDelayMs and has +/- 25% jitter applied automatically

Custom retry condition (shouldRetry)

Override which errors trigger a retry. Receives the error and the current attempt number.

import { EnvshedClient, EnvshedError } from "@envshed/node";

const client = new EnvshedClient({
  token: "envshed_...",
  retry: {
    maxRetries: 5,
    shouldRetry: (error, attempt) => {
      // Retry 429 (rate limited) in addition to the default 5xx
      if (error instanceof EnvshedError) {
        return error.status >= 500 || error.status === 429;
      }
      // Always retry network errors
      return true;
    },
  },
});

The ShouldRetryFunction signature:

type ShouldRetryFunction = (error: Error, attempt: number) => boolean;
  • error — an EnvshedError (HTTP error) or EnvshedNetworkError (network failure)
  • attempt — 1-based attempt number
  • Return true to retry, false to throw immediately

Retry callback (onRetry)

Hook into each retry for logging, metrics, or monitoring.

const client = new EnvshedClient({
  token: "envshed_...",
  retry: {
    onRetry: (error, attempt) => {
      console.warn(`[envshed] Retry attempt ${attempt}:`, error.message);
    },
  },
});

The OnRetryFunction signature:

type OnRetryFunction = (error: Error, attempt: number) => void;
  • Called before the delay/sleep for each retry
  • Not called on the initial request or when retries are disabled

Full example: custom retry strategy

import { EnvshedClient, EnvshedError, EnvshedNetworkError } from "@envshed/node";

const client = new EnvshedClient({
  token: process.env.ENVSHED_TOKEN!,
  retry: {
    maxRetries: 5,
    initialDelayMs: 200,
    maxDelayMs: 30000,

    // Linear backoff
    backoff: "linear",

    // Retry on 429, 5xx, and network errors
    shouldRetry: (error, attempt) => {
      if (error instanceof EnvshedError) {
        return error.status === 429 || error.status >= 500;
      }
      return true; // network errors
    },

    // Log retries
    onRetry: (error, attempt) => {
      const status = error instanceof EnvshedError ? error.status : "network";
      console.warn(`[envshed] Retry ${attempt}/5 (${status}): ${error.message}`);
    },
  },
});

Common Patterns

Load secrets into process.env

import { EnvshedClient } from "@envshed/node";

const client = new EnvshedClient({ token: process.env.ENVSHED_TOKEN! });

const { secrets } = await client.secrets.get({
  org: "my-org",
  project: "my-project",
  env: "production",
});

// Inject into process.env
Object.assign(process.env, secrets);

Sync secrets from a .env file

import { readFileSync } from "node:fs";
import { EnvshedClient } from "@envshed/node";

const client = new EnvshedClient({ token: process.env.ENVSHED_TOKEN! });

// Parse a .env file
const envContent = readFileSync(".env", "utf-8");
const secrets: Record<string, string> = {};
for (const line of envContent.split("\n")) {
  const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
  if (match) {
    secrets[match[1]] = match[2];
  }
}

// Push to Envshed
await client.secrets.set(
  { org: "my-org", project: "my-project", env: "development" },
  secrets,
);

Poll for environment changes

import { EnvshedClient } from "@envshed/node";

const client = new EnvshedClient({ token: process.env.ENVSHED_TOKEN! });
const envPath = { org: "my-org", project: "my-project", env: "production" };

let lastEtag: string | undefined;

setInterval(async () => {
  const result = await client.version.get(envPath, lastEtag);

  if (result === null) {
    // No changes
    return;
  }

  lastEtag = `"v${result.version}"`;
  console.log(`Environment updated to version ${result.version}`);

  // Re-fetch secrets
  const { secrets } = await client.secrets.get(envPath);
  Object.assign(process.env, secrets);
}, 30_000); // Poll every 30 seconds

Create a pre-deploy snapshot

import { EnvshedClient } from "@envshed/node";

const client = new EnvshedClient({ token: process.env.ENVSHED_TOKEN! });
const envPath = { org: "my-org", project: "my-project", env: "production" };

// Snapshot before deploying
const snapshot = await client.snapshots.create(envPath, {
  name: `pre-deploy-${new Date().toISOString()}`,
  description: "Automatic snapshot before deployment",
});
console.log(`Snapshot created: ${snapshot.id}`);

// ... deploy ...

// If something goes wrong, restore
await client.snapshots.restore(envPath, snapshot.id);
console.log("Rolled back to pre-deploy state");

TypeScript

The SDK is written in TypeScript and exports all types. You can import any type you need:

import type {
  EnvshedClientOptions,
  RetryOptions,
  BackoffFunction,
  ShouldRetryFunction,
  OnRetryFunction,
  EnvPath,
  GetSecretsResponse,
  SetSecretsResponse,
  Organization,
  Project,
  Environment,
  SecretVersion,
  Snapshot,
  ServiceToken,
  MeResponse,
} from "@envshed/node";

License

MIT