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

@ascdong/nexus

v0.1.6

Published

Unified Azure data access CLI for Log Analytics, Kusto, SQL Server / Azure SQL, PostgreSQL, and Storage Account

Downloads

1,089

Readme

nexus

Unified Azure data access CLI for Log Analytics, Kusto (Azure Data Explorer), Azure SQL Database, PostgreSQL, and Storage Accounts (Table/Blob/Queue). One command surface, named connectors, and Agent-friendly output.

Why

nexus connects multiple Azure data resources through named connectors and exposes a single way to query them and inspect their schema. It is built primarily for Agent consumption (stable parsing, token-efficient output) while staying usable by humans.

Architecture

nexus is a thin, uniform data-access layer in front of several data services that otherwise each have their own SDK, auth flow, query dialect, and result shape. A caller (an Agent or a human) issues one kind of command; nexus resolves the named connector, attaches the right credential, dispatches to the right backend adapter, and returns one normalized result shape in the caller's chosen format.

   +------------------------------------------------------------+
   |   Caller:   an Agent   or   a human at a terminal          |
   +------------------------------+-----------------------------+
                                  |  one command surface
                                  |  query / schema / sa / connector
                                  v
   +------------------------------------------------------------+
   |  nexus CLI                                                 |
   |                                                            |
   |  commands --> registry(by type) --> Connector interface:   |
   |                                       query                |
   |                                       listTables           |
   |                                       describeTable        |
   |                                       testConnection       |
   |                                                            |
   |  config:     ~/.nexus/config.json                          |
   |              (named connectors = coordinates only,         |
   |               never secrets)                               |
   |  credential: AAD / DefaultAzureCredential                  |
   |              (+ on-disk token cache, per-service scope)    |
   |                                                            |
   |  output:     ResultSet --> table | json | envelope         |
   |              (types normalized to one vocabulary:          |
   |               string long real datetime bool dynamic)      |
   +-----+---------------+---------------+---------------+------+
         |               |               |               |
         v               v               v               v
   +-----------+   +-----------+   +-----------+   +-----------+
   |log-       |   |kusto      |   |azure-     |   |storage-   |
   |analytics  |   |(ADX)      |   |sql        |   |account    |
   |(KQL)      |   |(KQL)      |   |(SQL)      |   |(no query  |
   |           |   |           |   |           |   |language)  |
   |Connector  |   |Connector  |   |Connector  |   |via sa:    |
   |adapter    |   |adapter    |   |adapter    |   |tbl/blob/q |
   +-----+-----+   +-----+-----+   +-----+-----+   +-----+-----+
         v               v               v               v
   Azure Monitor    ADX cluster    Azure SQL DB    Storage acct

How it acts as a unified data-access layer:

  1. One surface, many backends. query and schema work identically whether the target speaks KQL (Log Analytics, Kusto) or SQL (the mssql connector for SQL Server / Azure SQL, and postgres). You name a connector alias; nexus looks up its type and routes to the matching adapter — you never touch a per-service SDK or remember per-service flags.
  2. A single Connector contract. Every query-language backend implements the same four methods — query, listTables, describeTable, testConnection. A registry maps connector type → adapter, so adding a new resource type is one new adapter plus one registration; commands and core are untouched.
  3. Shared identity, per-service scope. All backends authenticate through one AAD credential (DefaultAzureCredential) with an on-disk token cache; each adapter just supplies its own token scope. Sign in once (az login) and every connector works.
  4. One normalized result. Backends return a common ResultSet (columns + rows), with column types normalized to a single vocabulary (string/long/real/datetime/bool/dynamic) regardless of source. The output layer renders that as table (humans) or json/envelope (Agents).
  5. Honest about shape differences. Storage Accounts aren't a query language, so they're deliberately not forced through query/schema; they get their own read-only nexus sa command group (Table/Blob/Queue) while still sharing the same connector config, credential, and output layer.

Install

End users install from npm — no Bun required, it runs on Node:

npm install -g @ascdong/nexus    # or: npm install @ascdong/nexus

Requires Node 20+.

Authentication

nexus authenticates to Azure with Microsoft Entra ID (AAD) via DefaultAzureCredential. Before running queries, sign in with one of the standard mechanisms it understands:

az login        # most common for local use

DefaultAzureCredential also picks up environment variables, Managed Identity, and VS Code sign-in automatically.

Token cache

Acquiring an AAD token cold is slow (~2–3s, because DefaultAzureCredential spawns the az CLI). To avoid paying that on every command, nexus caches the acquired token to ~/.nexus/token-cache.json (file mode 0600), keyed by scope, and refreshes it 1 minute before expiry. The first query in ~an hour is cold; subsequent queries reuse the cached token (token lookup drops from ~2s to ~0ms).

Security note: unlike config.json, the token cache does contain a live access token — anyone who can read the file can act as you against those resources until the token expires (typically ~1 hour). It is written 0600 (owner-only) and never committed to git. Clear it any time with:

nexus auth clear-cache

The query round-trip and process startup are not affected by the cache; only token acquisition is.

Connectors

Connectors are named aliases stored in ~/.nexus/config.json (override the directory with NEXUS_CONFIG_DIR). Most connectors hold connection coordinates only — never tokens or secrets (they authenticate via AAD).

Exception — secret-bearing auth modes. Two opt-in modes persist a secret in config.json: a storage-account added with --connection-string (which embeds an account key) and a postgres connector (which stores its --password). When you use these, treat ~/.nexus/config.json as sensitive — it is written owner-readable; do not commit it or share it. Prefer the AAD modes where a secret-free option exists (e.g. storage-account --account).

# Log Analytics
nexus connector add prod-logs --type log-analytics --workspace-id <workspace-guid>

# Kusto / Azure Data Explorer
nexus connector add telemetry --type kusto \
  --cluster-uri https://help.kusto.windows.net --database Samples

# SQL Server / Azure SQL Database
nexus connector add warehouse --type mssql \
  --server myserver.database.windows.net --database Sales

# PostgreSQL (username/password; works with Azure Database for PostgreSQL)
nexus connector add pgwarehouse --type postgres \
  --host myserver.postgres.database.windows.net --database appdb \
  --user appuser --password <password> --ssl require   # --ssl disable for local/dev

# Storage Account (Table + Blob + Queue) — AAD auth
nexus connector add mydata --type storage-account --account <storageacct>

# Storage Account — connection-string auth (embeds an account key)
nexus connector add mydata-cs --type storage-account \
  --connection-string 'DefaultEndpointsProtocol=https;AccountName=<acct>;AccountKey=<key>;EndpointSuffix=core.windows.net'

nexus connector list            # list all connectors (table; secrets redacted)
nexus connector list --output json   # machine-readable (secrets still redacted)
nexus connector test prod-logs  # verify connectivity
nexus connector remove prod-logs

connector list renders a human-readable table (alias, type, status, auth, detail) and never prints secrets — a storage connection string or postgres password always shows as <redacted>, in every output format.

Disable / enable

A connector can be disabled to block all data access through it (query, schema, sa, and connector test) without deleting its config:

nexus connector disable silicon-db   # anyone can disable (the safe direction)
nexus connector enable  silicon-db   # interactive terminal only — re-type the alias to confirm

While disabled, every data-access command for that alias fails with a CONFIG_ERROR (exit 2); management commands (list, remove, enable) still work. enable is human-gated: it refuses to run unless invoked from an interactive TTY and the operator re-types the alias. A non-interactive caller (e.g. an automated agent piping stdin) is rejected before any change is made.

This is a guardrail against accidental/automated re-enabling, not a cryptographic boundary: a human and an agent share the same OS user and binary, so anything the human can type, the same shell could. The TTY gate raises the bar (an agent driving nexus non-interactively cannot enable), but it does not defend against an adversary that can allocate a real terminal.

Query

nexus query <alias> "<statement>" [--output <fmt>] [--max-rows N] [--timeout MS]

The statement is KQL for Log Analytics / Kusto, and SQL for Azure SQL / PostgreSQL:

nexus query telemetry "StormEvents | take 5"
nexus query warehouse "SELECT TOP 5 * FROM Orders"

--max-rows caps the returned rows (default 1000) to protect downstream context; when the cap is hit, the result is flagged truncated.

Schema introspection

nexus schema tables <alias>                 # list tables
nexus schema describe <alias> <table>       # columns + normalized types

Storage Account

A storage-account connector exposes three services under nexus sa (alias of storageaccount). It is not used with query/schema — those are for the query languages. All operations are read-only.

# Table Storage — query is table + OData filter + select (not a single-string language)
nexus sa table list  mydata
nexus sa table query mydata MyTable --filter "PartitionKey eq 'orders'" --select RowKey,Amount

# Blob
nexus sa blob containers mydata
nexus sa blob list mydata mycontainer --prefix logs/
nexus sa blob read mydata mycontainer report.csv               # bytes -> stdout
nexus sa blob read mydata mycontainer image.png -o image.png   # binary -> file

# Queue
nexus sa queue list  mydata
nexus sa queue peek  mydata myqueue --count 10                 # does not dequeue
nexus sa queue count mydata myqueue

The tabular commands (table list/query, blob containers/list, queue list/peek) honor --output table|json|envelope. blob read returns raw bytes and ignores output formatting by design — use -o <file> for binary blobs. All three services authenticate with the same AAD identity (scope https://storage.azure.com/.default); data access requires a data-plane role such as Storage Blob/Table/Queue Data Reader (control-plane roles like Owner do not grant data access).

Output formats

--output selects the format. Default is table (human-readable). Agents should use json or envelope.

| Format | Shape | Best for | |---|---|---| | table (default) | aligned columns | humans | | json | array of objects keyed by column name | quick scripting | | envelope | columns declared once + rows as arrays + metadata | Agents (token-efficient) |

Example envelope output:

{
  "status": "ok",
  "columns": [{ "name": "Name", "type": "string" }, { "name": "Count", "type": "long" }],
  "rows": [["a", 1], ["b", 2]],
  "row_count": 2,
  "truncated": false
}

The envelope form declares column names once (instead of repeating them on every row), which keeps large result sets compact in an Agent's context window. Column types are normalized to a unified vocabulary (string, long, real, datetime, bool, dynamic) across all three resource types.

Output channels & exit codes

  • Results go to stdout; diagnostic logs go to stderr — so an Agent can parse stdout cleanly.
  • Exit codes: 0 success, 1 query/connection/auth error, 2 usage/config error.

On error, json/envelope mode writes a structured { "status": "error", "code": "...", "message": "..." } to stdout (so the single stream stays self-describing — status is "ok" or "error"), while the default table mode prints error [CODE]: message to stderr. Either way the exit code is non-zero.

Extending

  • New resource type: implement the Connector interface in src/connectors/, then register it in src/cli.ts — no changes to commands or core.
  • New auth method: implement CredentialProvider in src/core/credential.ts and select it in createCredential — connectors are unaffected, since each connector supplies its own token scope.

Development

Development uses Bun for fast installs, running, and tests. The published package is plain Node — Bun is a dev-time tool only.

bun install            # install deps (generates bun.lock)
bun test               # run the test suite
bun run dev <args>     # run from source, no build step
bun run typecheck      # tsc --noEmit
bun run build          # tsc → dist/ (the Node-runnable artifact that ships)

Publishing: bun run build (via prepublishOnly) compiles src/ to standard Node ESM in dist/ with a #!/usr/bin/env node shebang, then bun publish (or npm publish) uploads it. End users npm install and run it on Node — they never need Bun.

Known limitation: the mssql connector under the Bun runtime

Querying via the mssql connector (SQL Server / Azure SQL) fails under bun run (ESOCKET — Connection lost / socket hang up). This is an open Bun regression in its node:net compatibility layer that breaks the tedious (mssql) TDS-over-TLS handshake on some kernels (including WSL2); it is not a bug in this project — the same mssql call works under Node. Kusto and Log Analytics use plain HTTPS and are unaffected.

The fix is to run mssql queries on Node during development:

bun run build                                   # produce dist/ once
node dist/cli.js query <mssql-alias> "SELECT ..." # mssql: use node
bun run dev query <kusto-or-la-alias> "..."      # Kusto / LA: bun is fine

The published package runs on Node, so end users are never affected — all three resource types work normally via npm install.

See docs/superpowers/specs/ and docs/superpowers/plans/ for the full design and implementation plan.