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

@launchfile/sdk

v0.12.0

Published

TypeScript SDK for parsing, validating, and serializing Launchfiles

Readme

@launchfile/sdk

TypeScript SDK for parsing, validating, and serializing Launchfiles.

Install

bun add launchfile
# or
npm install launchfile

CLI

The SDK includes a launchfile CLI for validating and inspecting Launchfiles.

# Validate a Launchfile (defaults to ./Launchfile)
launchfile validate
launchfile validate path/to/Launchfile

# Structured JSON output for CI pipelines
launchfile validate --json

# Silent mode — just the exit code
launchfile validate --quiet

# Evaluate as if fetched standalone rather than read from the app's own
# checkout — enables the D-43 reduced-portability check (PROVIDERS.md §6)
launchfile validate --detached

# Print the normalized form (after shorthand expansion) as JSON
launchfile inspect path/to/Launchfile

# Dump the JSON Schema to stdout
launchfile schema

Global flags

  • --no-color — Disable colored output (also respects NO_COLOR env var)
  • --version — Print version
  • --help — Show usage

Reduced-portability warnings (D-40, D-43)

validate warns, non-fatally, when a component has no portable build path (runtime and/or commands.build/commands.install) or — with --detached — is source-needing with no repository: to fall back to. Set LAUNCHFILE_NO_PORTABILITY_WARNINGS (to any value except 0/false) to silence both; every other validate warning keeps firing. The lintLaunch(launch, opts?) SDK export takes the same two options (detached, suppressPortabilityWarnings) directly.

Validate in CI

# GitHub Actions
- run: npx launchfile validate --quiet

Editor Integration

Add JSON Schema support for autocompletion and validation in your editor:

# yaml-language-server: $schema=https://launchfile.dev/schema/v1
version: launch/v1
name: my-app

Usage

Parse a Launchfile

import { readLaunch } from "launchfile";

const app = readLaunch(`
  name: my-app
  runtime: node
  requires: [postgres]
  commands:
    start: "node server.js"
  health: /health
`);

// app.components.default.requires → [{ type: "postgres" }]
// app.components.default.health → { path: "/health" }

Validate pre-parsed data

import { validateLaunch } from "launchfile";

const app = validateLaunch({
  name: "my-app",
  runtime: "node",
  requires: ["postgres"],
});

Write back to YAML

import { writeLaunch } from "launchfile";

const yaml = writeLaunch(app);
// Collapses shorthands: { type: "postgres" } → "postgres"

Resolve expressions

import { resolveExpression } from "launchfile";

const url = resolveExpression("postgresql://${host}:${port}/${name}", {
  resource: { host: "localhost", port: 5432, name: "mydb" },
});
// → "postgresql://localhost:5432/mydb"

Check for expressions

import { isExpression } from "launchfile";

isExpression("$url");           // true
isExpression("hello");          // false
isExpression("$$escaped");      // false (literal $)

API

Every value export of src/index.ts is either a row below or an entry in EXCLUDED_EXPORTS (scripts/check-readme-exports.ts, with a one-line reason — mostly CLI-command implementations and the provider error-context vocabulary). bun run check:exports (wired as a pretest hook) fails bun run test — and CI's sdk job — if a value export is undocumented, or if a row/exclusion goes stale.

Parse, validate, serialize

| Function | Description | |----------|-------------| | readLaunch(yaml) | Parse YAML string → validated, normalized NormalizedLaunch | | parseLaunchYaml(yaml) | Parse YAML string → raw, un-normalized, un-validated data. Used internally by readLaunch; exposed for callers that need the document before validation strips unrecognized keys | | validateLaunch(data) | Validate a parsed object → NormalizedLaunch | | writeLaunch(launch) | Serialize NormalizedLaunch → compact YAML string | | LaunchSchema | Zod schema for direct validation | | parseRepository(repository) | Split a repository value at its # fragment → { url, ref } |

Expressions

| Function | Description | |----------|-------------| | parseExpression(value) | Parse a $-expression into an AST | | resolveExpression(value, context) | Resolve expression against a context → string | | isExpression(value) | Check if a string contains $ references | | parseDotPath(path) | Parse "a.b.c" → ["a", "b", "c"] | | deriveAppUrlProperties(url) | Split a URL into the { authority, scheme, tls } triple $app.* expressions resolve against |

Named endpoints (D-63)

$app.endpoints.<name>.* addresses one named published endpoint's public address; $components.<component>.<endpoint>.* addresses a named listener from inside the deployment.

| Function | Description | |----------|-------------| | endpointProperties(provides, host, activeCertificates?) | The <endpoint>.{host, port, protocol, url} map a provider registers for a component's named provides entries, reading each entry's effective listener (D-61 rule 2) | | appEndpointReferences(launch) | Every $app.endpoints… reference in the file's env: defaults and set_env: values, in declaration order — so a provider can warn only about the endpoints the app actually asks for | | APP_ENDPOINT_PROPERTIES | The properties $app.endpoints.<name>.* addresses: the standard $app.* set (D-33, D-35) less name | | UNPUBLISHED_APP_ENDPOINT | The answer for an endpoint the provider publishes no address for (D-63 rule 4) — every property "", degrading as an unknown $app.* property does (L-4) |

Publication context (D-58)

The orchestrator-supplied public URL a provider resolves $app.* from when routing is owned upstream. A malformed value is refused, never degraded.

| Function | Description | |----------|-------------| | normalizeAppUrl(value) | Validate and normalize a supplied publication URL → the WHATWG serialization with a lone root path dropped. Idempotent; throws InvalidAppUrlError on anything but an absolute http/https URL with no userinfo, query, or fragment | | suppliedAppAddress(appUrl) | The address a supplied URL determines (D-58 rule 2): { host, port, url, authority, scheme, tls } — the $app.* set less name | | suppliedAppProperties(name, appUrl) | name plus suppliedAppAddress, for a provider resolving the whole $app.* set in one step | | InvalidAppUrlError | Thrown for a refused appUrl (D-58 rule 3). The constructor masks userinfo in the displayed value, so no refusal path can echo an embedded credential (D-18, CWE-532) |

Listeners and certificates (D-61)

A provides entry's protocol/port are its declared listener; its effective listener is what that listener speaks in the configuration the deployment selected. They differ only when a bound certificate is active.

| Function | Description | |----------|-------------| | effectiveListener(entry, activeCertificates?) | Read one provides entry's listener in both readings. Omit activeCertificates and the entry reads as its baseline | | boundCertificate(entry) | The certificate name an entry binds, in either spelling (tls: server-cert or tls: { certificate: server-cert }), else undefined | | certificateBindings(component) | Every certificate binding on one component, as provides entry → certificate name | | CERTIFICATE | The supports: entry type a tls: binding names — type: certificate (D-61 rule 1) | | atDeclarations(launch) | Every provides entry that declares at: — its component, index, name and values (D-68). A provider sets up each value or reports it | | atEntryLabel(declaration) | How an at: declaration's entry is named in a message: `provides` entry "web" on web | | AT_APP_HOST | The at: value that names the app host itself — "@" (D-68 rule 2) |

Resource uses

A uses item is either a bare token (db) or a single-key map ({ db: cache }) naming one occurrence of a repeatable use. The use key — db, or db.cache — is the prefix providers register properties under and $<resource>.<use>.… addresses.

| Function | Description | |----------|-------------| | declaredUse(item) | Decode one uses item → { use, name? } | | useKey(item) | The use key of one item as written: db, or db.cache for { db: cache } | | useKeyOf(declared) | The use key of an already-decoded DeclaredUse | | useKeys(uses) | The use keys of a uses list, in declaration order | | parseUseKey(key) | Split a use key back into { use, name? } | | formatUseKey(key) | The spelling diagnostics use: db for a bare key, db: cache for a named one | | isRepeatableUse(type, use) | Whether the standard vocabulary lets use occur more than once on one type entry; undefined outside the registry, where the provider decides (L-4) | | RESOURCE_USE_VOCABULARY | Standard use vocabulary by resource type → use → the properties it registers. Advisory: lint warns, the schema never rejects | | UnresolvedUseError | Thrown when a $<resource>.<use>.<property> path names a use the entry does not declare, or a property the use does not register. Not softened by :-default — the path is wrong, not empty |

Command capture

One formatter for every surface a provider prints captures on, so sensitive means the same thing on each (SPEC.md § Command Capture). Masking is display only — keeping a value out of logs and state files is the provider redactor's job.

| Function | Description | |----------|-------------| | formatCaptures(captures, captureMeta, reveal, options?) | The indented lines a provider prints for one command's captures. reveal: true prints every value; otherwise a sensitive: true entry prints as CAPTURE_MASK, and one REVEAL_HINT line follows unless options.hint is false | | sensitiveCaptureValues(captures, captureMeta) | The values of every capture whose entry declares sensitive: true — what a provider registers with its redactor | | CAPTURE_MASK | The mask a sensitive value displays as | | REVEAL_HINT | The trailing line naming the command that prints masked values |

Component selection

| Function | Description | |----------|-------------| | selectComponents(launch, requested) | Resolve a requested component/resource name list against the launch → known, unknown, and resource names | | selectionClosure(launch, requested) | selectComponents, extended with the D-41 dependency-closure start set |

Linting

validate runs these; call them directly to build a custom check.

| Function | Description | |----------|-------------| | lintLaunch(launch, opts?) | Run every structural/portability lint over a normalized launch → warning strings | | lintDeprecations(launch) | Report deprecated fields present in the file (P-14/D-42), each carrying migration guidance | | lintDurations(launch) | Check every duration-valued field against the ratified duration grammar (P-9) | | lintUnknownStorageKeys(raw) | Check the raw (pre-normalization) document for storage: keys the schema doesn't recognize | | DURATION_PATTERN | The duration grammar regex every duration field is checked against (P-9) | | isValidDuration(value) | True when value matches DURATION_PATTERN | | parseDurationMs(value) | Parse a duration string ("30s", "5m", …) → milliseconds |

Environment, storage, and host capabilities

| Function | Description | |----------|-------------| | unsuppliedRequiredEnv(component, suppliedKeys) | List the component's required: variables that no value source in the file actually supplies | | indexOperatorStoragePaths(launch, suppliedPaths) | Index operator-supplied storage paths against the launch's content: operator volumes (D-50), for per-volume lookup | | UnboundOperatorStorageError | Thrown when a content: operator volume has no supplied path (D-50 row 2) | | MissingOperatorStoragePathError | Thrown when an operator-supplied storage path does not exist or is not readable on the host (D-50 row 3); the directory is never created | | collectHostCapabilities(launch) | Collect the app's requested host capabilities (D-44) as "name=value (required\|optional)" strings | | collectOperatorStorage(launch) | Collect the volumes marked content: operator (D-50) as "component.volume" strings | | RESOURCE_PROPERTY_VOCABULARY | Standard resource property vocabulary by resource type (SPEC.md § Resource Property Vocabulary, D-46) |

Source mode

| Function | Description | |----------|-------------| | resolveSourceRunCommand(component) | Resolve which command runs a source-mode component: commands.dev wins, then commands.start — but image (no dev) returns undefined rather than falling back to start | | resolveSourcePrepareCommand(component) | Resolve which command prepares a source-mode component (commands.install → commands.build) |

Deployment state

A pure event-sourced state model — fold LaunchEvents into a DeploymentState, diff two states back into events, and resolve $-references against a state.

| Function | Description | |----------|-------------| | reduce(state, event, at?) | Fold one LaunchEvent into DeploymentState → the next state | | diff(prev, next) | Compare two DeploymentStates → the LaunchEvents that would fold prev into next | | resolveRef(state, ref, vantage) | Resolve a $-reference against a DeploymentState → string (never throws on an unresolved reference) |

Toolchain detection

| Function | Description | |----------|-------------| | extractToolchainVersions(repoDir) | Discover per-language toolchain versions declared in a repo checkout (package.json, .tool-versions, …) → Promise<ToolchainVersions> |

Types

All types are exported:

import type {
  Launch,
  NormalizedLaunch,
  Component,
  NormalizedComponent,
  Requirement,
  Provides,
  EnvVar,
  // ... see types.ts for full list
} from "launchfile";

License

MIT