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 🙏

© 2025 – Pkg Stats / Ryan Hefner

declastruct

v1.4.5

Published

Add declarative control to any resource constructs. Declare, plan, and apply within an observable pit-of-success.

Downloads

2,534

Readme

declastruct

test publish

declarative control of any resource constructs, batteries included

intro

Control any resource construct declaratively. Declare what you want ✨. Plan to see what must change 🔮. Apply to make it so 🪄

what is it?

declastruct is a framework to control any resource construct via declarative instructions — you describe what you want the end state to be, and the system figures out how to get there.

declarative instructions means:

  • you declare the desired state of your resources
  • the system compares your desires against reality
  • the system computes the changes required to reconcile reality with your desires
  • you review and apply those changes

in contrast to imperative instructions, where you specify each step and hope it produces what you want:

// imperative 👎 = you say HOW to do things, step by step
await createBucket({ name: 'my-bucket' });
await enableVersioning({ bucket: 'my-bucket' });
await setEncryption({ bucket: 'my-bucket', type: 'AES256' });

the advantage of declarative instructions is that you simply declare what you want and know it will work:

// declarative 👍 = you say WHAT you want, the system figures out how
const bucket = DeclaredAwsS3Bucket.as({
  name: 'my-bucket',
  versioning: true,
  encryption: 'AES256',
});
await apply({ resources: [bucket] });

works with:

  • infrastructure — AWS, GCP, Azure resources
  • SaaS platforms — Stripe customers, GitHub repos, Slack channels, etc
  • databases — application data models
  • any API — anything with a remote state you want to control

think Terraform, but:

  • no state files to manage — compares directly against live remote state
  • no new language to learn — declare via TypeScript, reuse domain objects and operations
  • pit-of-success by default — enforces idempotency, clear unique keys, and safe operations
  • not just infrastructure — works with any resource construct (saas, databases, apis, etc)

usage

install

npm install declastruct --save-dev

use

1. declare your desired state ✨

declare your wish via strongly-typed domain-objects. these are the declarative instructions that will control your resources.

import { getDeclastructAwsProvider, DeclaredAwsS3Bucket } from 'declastruct-aws';
import { getDeclastructStripeProvider, DeclaredStripeCustomer } from 'declastruct-stripe';

// define which providers support your resource constructs
export const getProviders = async () => [
  await getDeclastructAwsProvider({
    profile: process.env.AWS_PROFILE,
  }),
  await getDeclastructStripeProvider({
    apiKey: process.env.STRIPE_SECRET_KEY,
  }),
];

// declare the resource constructs you want and their desired state
export const getResources = async () => {
  const bucket = DeclaredAwsS3Bucket.as({
    name: 'your-s3-bucket',
    versioning: true,
    encryption: 'AES256',
  });

  const customer = DeclaredStripeCustomer.as({
    email: '[email protected]',
    name: 'John Doe',
    metadata: { source: 'app-web' },
  });

  return [bucket, customer];
};

2. plan the required changes 🔮

see exactly what must change to make your wish come true, ahead of time

npx declastruct plan \
  --wish provision/resources.ts \
  --into provision/.temp/plan.json

output:

planned changes:
  CREATE: DeclaredAwsS3Bucket.your-s3-bucket
    + name: "your-s3-bucket"
    + versioning: true
    + encryption: "AES256"

  CREATE: [email protected]
    + email: "[email protected]"
    + name: "John Doe"
    + metadata: { source: "app-web" }

3. apply the plan 🪄

apply the plan to make your wish come true

npx declastruct apply --plan provision/.temp/plan.json

benefits - why declastruct?

summary

stateless — no state files to manage, compare directly against reality

type-safe — full TypeScript support with domain objects

idempotent — safe to plan and apply repeatedly

observable — see exactly what would change if you apply

composable — reuse domain objects and operations across application code and declarative instructions

pit-of-success — enforced best practices via idempotent dao interfaces

universal — works with any resource construct (infrastructure, saas platforms, databases, apis, etc)

details

no state file management

traditional declarative tools (like Terraform) require separate state files to track resources existence. this creates problems:

  • state files can drift from reality
  • state lock issues in team environments
  • state files must be carefully secured and backed up

declastruct eliminates state files entirely. it compares your declared desires directly against live remote state via unique keys, so the source of truth is always reality itself.

use your existing domain language

instead of HCL, YAML, or another DSL:

  • write declarative instructions via TypeScript with domain-objects
  • reuse the domain objects and domain operations across your application code and declarative instructions
  • leverage TypeScript's type safety, IDE autocomplete, and refactor tools
  • compose and test declarative instructions like any other code

enforced best practices

declastruct providers follow a pit-of-success pattern that guarantees:

idempotency — all operations can be safely retried

  • finsert: find-or-insert (safe create)
  • upsert: update-or-insert (safe update)
  • repeat any operation multiple times, get the same result each time

explicit unique keys — every resource declares how to uniquely identify it

  • prevents accidental duplicates
  • enables accurate comparison against live state
  • makes resource relationships clear, typesafe, and composable

observable change plans — see exactly what must change before you apply

  • diff view shows before & after for each resource
  • change actions: CREATE, UPDATE, KEEP, DESTROY
  • no surprises in production

provider ecosystem

declastruct is designed to support any resource construct through adapters:

available providers:

  • declastruct-aws — AWS infrastructure (S3, Lambda, RDS, EC2, etc.)
  • declastruct-stripe — Stripe SaaS resources (customers, subscriptions, products, etc.)
  • declastruct-github — Github resources (repos, branches, protection, etc.)
  • etc

build your own provider for any resource construct (GitHub repos, Slack channels, database records, etc.) via the DeclastructDao and DeclastructProvider interfaces.

use cases

  • infrastructure as code — control AWS, GCP, Azure resources via declarative instructions
  • SaaS platform management — control Stripe customers, GitHub repos, Slack channels via declarative instructions
  • database state management — control database resource states via declarative instructions
  • api state management — control remote resource state via declarative instructions
  • multi-platform orchestration — coordinate resources across different providers in one plan

concepts

domain

DeclastructDao

the core abstraction that defines how to get and set a resource type:

interface DeclastructDao<TResource, TResourceClass, TContext> {
  get: {
    byUnique: (ref: RefByUnique, context) => Promise<TResource | null>;
    byPrimary?: (ref: RefByPrimary, context) => Promise<TResource | null>;
    byRef: (ref: Ref, context) => Promise<TResource | null>;
  };
  set: {
    finsert: (resource: TResource, context) => Promise<TResource>;
    upsert?: (resource: TResource, context) => Promise<TResource>;
    delete?: (ref: Ref, context) => Promise<void>;
  };
}

every resource class has a DeclastructDao that enforces safe, idempotent operations.

DeclastructProvider

bundles related DAOs and provider context:

interface DeclastructProvider<TDaos, TContext> {
  name: string;                    // provider identifier
  daos: TDaos;                     // map of resource types to DAOs
  context: TContext;               // auth, region, etc.
  hooks: {
    beforeAll: () => Promise<void>;
    afterAll: () => Promise<void>;
  };
}

DeclastructPlan

captures the changes needed to reconcile reality with declared desires:

interface DeclastructPlan {
  changes: DeclastructChange[];    // ordered list of changes
  createdAt: IsoTimestamp;         // when plan was created
  hash: string;                    // fingerprint for validation
}

each DeclastructChange includes:

  • action: CREATE | UPDATE | KEEP | DESTROY
  • forResource: which resource this affects
  • state.desired: what you want
  • state.remote: what exists now
  • state.difference: human-readable diff

inspiration

inspired by Terraform's declarative approach, but designed to eliminate state file overhead, work with any resource construct, be reusable across both prod codepaths and cicd control, and leverage TypeScript's type system for safer declarative instructions.