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

sdk-environment

v0.1.4

Published

parse and expose the environment your code runs in

Readme

sdk-environment

test publish

parse and expose the environment your code runs in

install

npm install sdk-environment

what

an environment is defined by three attributes:

interface Environment {
  access: 'test' | 'prep' | 'prod';
  server: string;  // 'local@unix' | 'local@cicd' | '[email protected]' | ...
  commit: string;  // '$gitref@$hash' or '$gitref@$hash+' if dirty
}

| attribute | what | why | |-----------|------|-----| | access | what resources can we touch? | controls which databases, apis, secrets, etc. are reachable | | server | where does this run? | enables server-specific behavior (log format, cache strategy, etc.) | | commit | what code is this? | enables traceability and debug |

access

which tier of resources this process can access.

| value | what | examples | |-------|------|----------| | test | ephemeral, isolated, disposable | in-memory db, mocked apis, test fixtures | | prep | persistent, shared, pre-production | prep db, sandbox apis, qa data | | prod | persistent, shared, production | production db, live apis, real users |

server

where this process executes. format: $tier@$platform

| value | what | examples | |-------|------|----------| | local@unix | developer machine | laptop, docker compose | | local@cicd | ci runner | github actions, circleci | | [email protected] | aws lambda | serverless functions | | [email protected] | aws ecs | containerized services | | [email protected] | aws ec2 | virtual machines | | [email protected] | gcp cloud run | containerized services |

the tier (local or cloud) is always parseable:

const tier = environment.server.split('@')[0]; // 'local' | 'cloud'

commit

what code this process runs. format: $gitref@$hash or $gitref@$hash+ if dirty

| context | format | example | |---------|--------|---------| | tagged release | v$tag@$hash | v1.2.3@a1b2c3d | | branch build | $branch@$hash | feat/auth@e4f5g6h | | local dev | $branch@$hash | main@i7j8k9l | | dirty (uncommitted changes) | $gitref@$hash+ | main@i7j8k9l+ |

the + suffix indicates uncommitted changes exist. enables:

  • trace logs back to exact code version
  • detect if deployed with uncommitted changes
  • debug production issues
  • track releases

use

import { getEnvironment } from 'sdk-environment';

const environment = await getEnvironment();

console.log(environment);
// {
//   access: 'prod',
//   server: '[email protected]',
//   commit: 'v1.2.3@a1b2c3d'
// }

pluggable parsers

each attribute is derived via an ordered list of parsers. first parser to return a value wins.

import {
  getEnvironment,
  fromEnvar,
  fromAwsAccountAlias,
  fromNodeEnv,
  fromLambdaTaskRoot,
  fromCiEnvar,
  fromUnixDesktop,
  fromGit,
} from 'sdk-environment';

// default parsers (what getEnvironment() uses out of the box)
const environment = await getEnvironment({
  parsers: {
    access: [
      fromEnvar('ACCESS'),           // explicit override via ACCESS=prod
      fromAwsAccountAlias(),         // infer from aws account alias (e.g., 'myorg-prod' → prod)
      fromNodeEnv(),                 // fallback: NODE_ENV=test → test
    ],
    server: [
      fromEnvar('SERVER'),           // explicit override via [email protected]
      fromLambdaTaskRoot(),          // LAMBDA_TASK_ROOT present → [email protected]
      fromCiEnvar(),                 // CI=true → local@cicd
      fromUnixDesktop(),             // XDG_SESSION_TYPE or TERM_PROGRAM → local@unix
    ],
    commit: [
      fromEnvar('COMMIT'),           // explicit override via COMMIT=v1.0.0@abc123
      fromGit(),                     // git describe + rev-parse + dirty check → v1.0.0@abc123+
    ],
  },
});

custom parsers

a parser is a function that returns a value or null:

type Parser<T> = () => T | null | Promise<T | null>;

add custom parsers for your infrastructure:

import { getEnvironment, fromEnvar } from 'sdk-environment';

// custom parser: infer access from k8s namespace
const fromK8sNamespace = (): 'test' | 'prep' | 'prod' | null => {
  const ns = process.env.K8S_NAMESPACE;
  if (ns?.endsWith('-prod')) return 'prod';
  if (ns?.endsWith('-prep')) return 'prep';
  if (ns?.endsWith('-test')) return 'test';
  return null;
};

const environment = await getEnvironment({
  parsers: {
    access: [
      fromEnvar('ACCESS'),
      fromK8sNamespace(),        // your custom parser
      fromAwsAccountAlias(),
      fromNodeEnv(),
    ],
  },
});

with config

pair with config to load secrets per-environment:

import { getEnvironment } from 'sdk-environment';
import { getConfig } from './config';

const environment = await getEnvironment();
const config = await getConfig({ environment });

// config.database.password loaded from:
// - test: local .env or mock
// - prep: aws ssm /myapp/prep/database.password
// - prod: aws ssm /myapp/prod/database.password

override via env vars

set explicit values when parsers can't infer correctly:

ACCESS=prod [email protected] COMMIT=v1.2.3@abc123 node app.js

design

why these three?

every runtime question reduces to one of:

  1. what can i touch?access
  2. where am i?server
  3. what code is this?commit

other concerns (region, account, cluster) are derivable or orthogonal.

access vs server

these are independent axes:

| access | server | example | |--------|--------|---------| | test | local@unix | npm test on laptop | | test | local@cicd | ci runner runs tests | | prep | local@unix | dev laptop against prep db | | prep | [email protected] | prep lambda | | prod | local@unix | production debug session | | prod | [email protected] | production lambda |

this separation enables precise behavior:

// fail loudly in test, warn in prod
if (environment.access === 'test') {
  throw new SchemaError('config drift detected');
} else {
  log.warn('config drift detected', { diff });
}

// verbose logs locally, structured logs in cloud
const tier = environment.server.split('@')[0];
if (tier === 'local') {
  log.pretty();
} else {
  log.json();
}

prep over dev

we use prep (preparation) instead of dev (development):

| term | describes | semantic fit | |------|-----------|--------------| | prod | where we produce value | what happens there | | prep | where we prepare for production | what happens there | | dev | who uses it (developers) | who, not what |

test → prep → prod reads as a progression of readiness.