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

@sayuthisobri/awan

v0.1.0

Published

Multi-cloud resource management TUI inspired by k9s

Readme

awan

A k9s-inspired terminal UI for browsing AWS resources. Bun + TypeScript + React on OpenTUI, with both a real AWS SDK-backed data path and a deterministic mock data path behind one ICloudService interface.

:ec2  :vpc  :sg  :lb  :nacl  :tgw  :rds  :eks  :ecs  :secrets
:route53  :s3  :iam  :acm  :tg  :volume  :rds-subnet-groups  …

(: opens the command prompt; : again cancels. See src/actions/commands.ts for the full list.)

Quick start

bun install
bun run dev              # launches the TUI (src/main.tsx)
bun test                 # bun's runner, vitest-compatible API
bun run typecheck        # tsc --noEmit, strict
bun run lint             # eslint flat config
bun run format           # prettier --write src/ tests/

Override the data source at runtime:

| Env var | Effect | | ---------------- | ----------------------------------------------------------------- | | AWAN_DATA=mock | Force mock data even for SSO profiles (useful for demos / tests). | | AWAN_DATA=sso | Require a real SSO profile; throws otherwise. | | AWANAN_CONFIG | Point at a single YAML file that replaces the merged config. |

By default awan reads ~/.aws/config for profiles and merges config.yaml with ~/.config/awan/config.yaml.

What ships today

| Module family | What you can browse | | --------------- | ---------------------------------------------------------------- | | EC2 / Storage | Instances, EBS volumes | | VPC | VPCs, subnets, security groups + rules, NACLs + rules, ENIs, LBs | | ELBv2 | Load balancers, listeners, listener rules, target groups | | RDS | DB instances, subnet groups, parameter groups | | EKS | Clusters, node groups | | ECS | Clusters, services | | Route53 | Hosted zones | | S3 | Buckets | | Secrets Manager | Secrets | | ACM | TLS certificates | | IAM | Roles | | Transit Gateway | TGWs, attachments, route tables |

SSO profiles are detected automatically; awan opens a modal prompt to refresh an expired token and re-runs the failed request once aws sso login succeeds.

Architecture in one screen

                 ┌────────────────────────┐
   keypress  ──▶ │  CommandPrompt / keys  │   runAction(path, args)
                 └──────────┬─────────────┘
                            ▼
              ┌────────────────────────┐
              │  Action registry       │   src/actions/registry.ts
              │  (path → handler)      │
              └──────────┬─────────────┘
                         ▼
  ┌─────────────────────────────────────────────┐
  │  pushView / popView / replaceView / …       │   src/actions/navigation.ts
  │  (mutates useAppStore.stack — only place)   │
  └──────────────────────┬──────────────────────┘
                         ▼
              ┌────────────────────────┐
              │  View stack: BaseView  │   src/components/Base/
              │  → ListView / Detail   │
              └──────────┬─────────────┘
                         ▼
  ┌─────────────────────────────────────────────┐
  │  useResourceList / useParallelFields        │   src/hooks/
  │  + getService(profile) → ICloudService      │
  └──────────┬──────────────────┬───────────────┘
             ▼                  ▼
  ┌──────────────────┐  ┌────────────────────┐
  │ MockAwsEc2Service│  │  SdkAwsService     │   src/services/aws/{ec2,sdk}/
  │ (deterministic)  │  │  (@aws-sdk/*)      │
  └──────────────────┘  └────────────────────┘

Two important invariants:

  1. The UI never imports @aws-sdk/* directly. All cloud calls go through getService(profile) (src/services/factory.ts) which picks the mock or the SDK implementation. Non-AWS providers get UnsupportedService, which throws on every method.
  2. Navigation goes through the helpers in @/actions, not the store directly. Calling useAppStore.pushView() from a view bypasses pruneFilters and breaks the single-source-of-truth invariant that tests/contracts/ enforces.

The full set of architectural rules — keybinds, refresh, breadcrumbs, SSO recovery, tests, hook inventory, service-layer invariants — is in CONSISTENCY.md. Read it before adding a view, a hook, or a service method.

Project conventions (imports, formatting, types, naming, error handling, commits) are in AGENTS.md.

How to add a new module

A "module" is one AWS service — e.g. ACM, RDS, Transit Gateway. The end-to-end checklist:

1. Define the resource types

Add interfaces to src/types/cloud.ts (or the appropriate sub-file). Mirror the SDK shape but only what the views need.

2. Add the ICloudService method

src/services/base.ts is the contract. Add the method signatures — both list and get — even if you only need one to start. Every method takes profileId so the implementation can route per-profile if it needs to later.

3. Wire the mock

MockAwsEc2Service in src/services/aws/ec2.ts implements the full ICloudService surface (name notwithstanding). Add your methods there plus a fixture array. Tests rely on this data path — never make real AWS calls in bun test.

4. Wire the SDK

Create src/services/aws/sdk/<your-service>.ts. Use buildCredentials(profile) and wrapSdkError(err, profile) from sdk/client.ts so SSO expiry surfaces as SsoExpiredError. Then add the methods to the composition in src/services/aws/sdk/index.ts.

5. Add the UnsupportedService stub

src/services/factory.ts exposes UnsupportedService for non-AWS providers. Add the same method names returning this.fail() so the interface compiles.

6. Build the views

Each module is a folder under src/components/Modules/AWS/<Name>/:

  • index.ts — re-export everything
  • <Name>ListView.tsx — list page (uses useResourceList)
  • <Name>DetailView.tsx — detail page (uses useParallelFields)

Every view must be wrapped in BaseView, declare its metadata.breadcrumb via the typed crumbs.<provider>.<module>.*() helpers in src/utils/breadcrumbs.ts, and register handlers for every non-local keybind. findUnregisteredKeybinds() (called from BaseView) logs drift warnings at mount.

7. Add breadcrumbs

src/utils/breadcrumbs.ts is the single source of truth for the strings used as view-state keys. Add list(), detail(id), plus any context-scoped helpers you need (e.g. targetGroups(lbArn)).

8. Surface it

Two entry points, both required:

  • ProviderView (src/components/Modules/Profile/ProviderView.tsx) — add a row so the user can navigate from the service menu.
  • commands.ts (src/actions/commands.ts) — add a registerAction('command/<short>', …) so the user can jump from anywhere with :<short>. Use the pushList({…}) helper so the navigation resets to the provider view first.

Update the example hint at the bottom of CommandPrompt.tsx to include your new short name.

9. Tests

  • Mock path: a tests/services/<svc>-mock.test.ts exercising the mock methods.
  • SDK path: stub @aws-sdk/client-<svc> via vi.mock(...) (see the existing SDK tests for the pattern).
  • Contract: add a tests/contracts/ test if you introduce a new convention. Existing contract tests catch things like direct useAppStore.subscribe usage, unregistered global/nav actions, and unregistered command/* paths.

10. Verify

bun run typecheck && bun run lint && bun test

Keep commits scoped per module: feat(acm): add certificate list view is the kind of granularity the project uses. Conventional commits, one module per commit.

Common gotchas

A non-exhaustive list; full table in AGENTS.md.

  • DescribeTargetGroupsCommand does not return target-group attributes (stickiness, deregistration delay). Use DescribeTargetGroupAttributesCommand for those.
  • DescribeRulesCommand does not return the parent ListenerArn on a rule; pass listenerArn through props if a view needs it.
  • DescribeNodegroupCommand parameter is nodegroupName (all lowercase) — the SDK key is case-sensitive.
  • SDK mappers must never throw on missing optional fields. Use ?? defaults and filter undefined ids before constructing rows.
  • Detail-row activation logic must guard on state.kind === 'ready' before reading data; ignore activation on rows still in loading or error.

Layout

src/
  actions/        # action registry + core actions (navigation, global, commands)
  components/
    Base/         # BaseView, ListView, DetailTable, ScrollBox, …
    Layout/       # AppShell, BreadcrumbBar, HelpBar, CommandPrompt, …
    Modules/
      Profile/    # profile list + provider service menu
      AWS/        # one folder per AWS service family
  hooks/          # useResourceList, useParallelFields, useRefreshTick, …
  logs/           # file-only logger with size-based rotation
  rendererRef.ts  # singleton handle to the OpenTUI CliRenderer
  services/
    base.ts       # ICloudService contract
    factory.ts    # getService(profile) + UnsupportedService
    aws/
      ec2.ts      # MockAwsEc2Service (full mock implementation)
      sdk/        # one file per AWS service, composed by sdk/index.ts
      discovery/  # ~/.aws/config parsing, SSO detection
  store/          # zustand stores (useAppStore, useActionStore, useCommandHistory)
  types/          # CloudProfile, ViewMetadata, per-service resource types
  utils/          # breadcrumbs, viewState, sso-recovery helpers, …

tests/
  services/       # mock data path coverage
  components/     # OpenTUI render tests (use tests/helpers/testRender.ts)
  store/          # zustand slice tests
hooks/          # hook contract tests
  utils/          # breadcrumb + viewState + logger helpers
  actions/        # command + ctx action tests
  config/         # loadConfig tests
  logs/           # logger rotation tests
  types/          # type-guard and helper tests
  contracts/      # cross-cutting invariants (run in CI to catch drift)
  helpers/        # shared test utilities (testRender, destroyRenderer)