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

@strato-dan/array

v0.5.3

Published

[DAN] ARRAY — P2P .env sync, no central server. Basic tier: generic AES-256-GCM encryption, LAN peer discovery, zero runtime dependencies.

Readme

[DAN] ARRAY

P2P .env sync over your LAN — no central server to leak, breach, or go down.

CI npm version runtime deps status license

⚡ Zero install · zero runtime dependencies. npx @strato-dan/array runs it — pure Node standard library (Node ≥ 18), nothing to install. Full breakdown under Dependencies.

P2P .env sync. No central server.

A real peer-to-peer tool for handing a .env file to a teammate (or another machine you own) on the same network — no server in the middle to leak, get breached, or go down.

⚠️ Experimental — trusted / private networks only. [DAN] ARRAY is experimental. Use it only on trusted, private networks you control (your own LAN or Wi-Fi) — not for real production secrets over shared or public Wi-Fi.

Use

npx @strato-dan/array

Opens at http://127.0.0.1:4873 (loopback only — the UI, not the transfer, is local-only).

On the sending machine: paste your .env contents, pick a room code and a passphrase (share these two out of band — Slack, in person, a call — never over the same channel as the file itself), click Broadcast & wait for peer.

On the receiving machine: enter the same room code and passphrase, click Listen for peer.

Scriptable & CI

The launcher is script-friendly — hand-rolled flags, zero dependencies:

dan-oss-array --version   # prints the version, exit 0
dan-oss-array --help      # usage, env vars, and the exit-code contract, exit 0
dan-oss-array --json      # startup banner as one JSON object {url,port,mode,encryption}

The default startup banner stays human-readable; --json emits a single machine-readable line instead, e.g. {"url":"http://127.0.0.1:4873","port":4873,"mode":"p2p-basic","encryption":"AES-256-GCM"}.

Environment: DAN_OSS_ARRAY_PORT overrides the loopback port (default 4873).

Exit codes: 0 clean startup (or --version/--help, or a clean Ctrl-C shutdown); 1 startup failure (e.g. the port is already in use — one honest stderr line, never a raw stack); 2 usage error (an unknown flag).

A Makefile wraps the common tasks — make help lists them (make test, make attack, make demo, make bench). Every test invocation pins --test-concurrency=1.

How it actually works

1. Sender encrypts the .env text locally (AES-256-GCM, key derived from the passphrase via scrypt)
2. Sender broadcasts a UDP announcement on the local network: "a room with this hash exists,
   connect to me on this port" — the room code itself never goes on the wire, only its hash
3. Receiver, listening for that same hash, connects DIRECTLY to the sender over TCP
4. The two run an authenticated handshake: a fresh X25519 key agreement whose session key is bound to
   BOTH the exchange AND the passphrase, and the receiver proves the passphrase before anything is
   sent. The sender refuses a peer that can't prove it and keeps waiting for the right one.
5. Sender hands over ONE sealed capsule (the credential, encrypted under that session key), then
   closes — one authenticated peer, one transfer, no relay
6. Receiver opens the capsule and decrypts locally with the passphrase

No cloud service, no relay server, no account. If both machines are on the same LAN/Wi-Fi network, they find each other directly.

Honest limits

  • Experimental — trusted networks only. This tool is experimental and intended for trusted, private networks (your own LAN / Wi-Fi). Do not use it to move real production secrets over shared or public Wi-Fi.
  • Same network only. UDP broadcast discovery works within one LAN/Wi-Fi broadcast domain. It does not cross the public internet or a NAT boundary — that would need a relay, which is exactly the central point of failure this tool exists to avoid.
  • The passphrase still matters. The transfer now rides an ephemeral X25519 session key bound to the passphrase, so a captured session can't be opened without the ephemeral secret — but a weak passphrase is still a weak passphrase. scrypt makes brute-forcing expensive, not impossible; use a real shared secret, not password123.
  • The receiver is authenticated (v0.2). The sender no longer streams the blob to the first peer that connects — the peer must prove the passphrase (bound to a fresh key agreement) before the sealed capsule is sent, and an unproven peer is refused while the sender waits for the right one. A racing LAN host can no longer steal the ciphertext or deny the real receiver. Honest residual: an active impostor that lures a receiver and wins its discovery race obtains one transcript MAC it can attack offline against the passphrase (scrypt-hardened) — it yields a passphrase guess, never a past session's payload.
    • Why this residual exists, and what removes it. The residual is inherent to authenticating with a shared passphrase and no PKI: the handshake produces a transcript MAC an active impostor can grind offline, so a low-entropy passphrase is only as safe as scrypt makes it slow. The construction that removes this class outright is a PAKE (password-authenticated key exchange): a PAKE is designed so a wrong guess simply aborts the session, leaving the attacker exactly one online guess per attempt and no offline-attackable transcript at all — the exchange yields nothing a captured session can grind later, which is what makes even a short code safe. Adopting a PAKE for the handshake is the concrete path to a higher-assurance tier; the current basic tier deliberately keeps the simpler passphrase+scrypt binding and states this limit honestly instead.
    • Handshake assurance and network reach are two independent axes. A PAKE upgrade would strengthen who you're talking to; it would not change the LAN-only limit above. Reaching a peer across NAT or the internet needs a brokering relay — the central dependency this tool trades away on purpose — so a higher-assurance handshake and cross-network reach are separate decisions, not one bundled step.
  • Discovery is unauthenticated, but a spoofer can't deny the transfer. Any LAN host can broadcast a matching announcement — discovery carries only the room-code hash and a TCP port, and nothing signs it. A spoofing host can therefore point a receiver at the wrong TCP endpoint. It gains nothing from doing so (that endpoint still has to pass the authenticated handshake, which it can't), and as of v0.3 it can no longer deny the transfer either: the receiver keeps listening and tries each distinct announcer in turn instead of committing to the first one. Flooding the discovery port to drown out the real announcer is a denial-of-service, which SECURITY.md explicitly de-scopes.
  • The sharer is a bounded online passphrase oracle during its window. While it is listening, each connecting peer gets exactly one attempt to prove the passphrase, so an attacker on the LAN can make online guesses for as long as the window stays open. This is throttled, not unthrottled: every attempt costs a full X25519 handshake and a deliberately slow scrypt derivation (N=16384), concurrent handshakes are capped, and the window is finite (2 minutes by default) — a few hundred guesses total against a real passphrase, which is why passphrase entropy is what matters. A hard per-window attempt cap is deliberately not added: an unauthenticated attacker could trip it on purpose to lock out the real receiver, turning a weak throttle into a reliable denial-of-service lever — and DoS is out of scope per SECURITY.md. Use a real shared secret and keep the window short.
  • The local UI server is loopback-only and cross-origin-guarded. The bundled HTTP server binds 127.0.0.1 only, refuses any request whose Host isn't loopback (so a web page can't DNS-rebind a hostname to 127.0.0.1 and drive it), and refuses any request carrying a non-loopback browser Origin (so a cross-origin page can't CSRF the local share/receive API). A determined attacker who can already send raw packets to the loopback port to disrupt it is a denial-of-service, de-scoped per SECURITY.md.
  • This secures the wire, not the endpoints. It removes the central-server leak risk — it does not protect either machine from its own compromise.
  • Nothing is ever written to disk by this tool. The .env text lives in the browser tab and the Node process's memory only, for the life of the transfer. The room code and passphrase are entered in the UI and never passed as a command-line argument — a secret in a process's argument list is visible to any other user on the machine (e.g. via the process list), so it stays out of argv.

Basic tier vs. the advanced tier

This is the open-source basic tier: generic AES-256-GCM encryption, P2P discovery, no central server. [DAN] ARRAY (advanced) replaces the generic cipher with DAN's own proprietary encryption architecture ([DAN] ENCRYPTED MODULE) and lives exclusively inside [DAN] MEMORY SMASH — it is not, and will not be, part of this repository.

When to use this

  • Best fit: handing a .env file, API key, or small secret to a teammate (or your own other machine) on the same LAN/Wi-Fi, right now, without emailing it, pasting it in chat, or standing up any kind of server or account to do it.
  • Best fit: you want the transfer itself encrypted end-to-end with no middleman that could leak or get breached, and you're comfortable sharing the room code/passphrase out of band.

Honest flip side: if the two machines aren't on the same network segment — different offices, different Wi-Fi, one on a VPN the other isn't — this doesn't work and isn't trying to; see "Same network only" above. It also isn't a general file-sharing tool: it moves one block of text (typically .env contents), not files or directories, and nothing is retried or queued — both sides need to be running within the timeout window of each other.

Validation

Everything below was run locally before this README shipped — no mocked output.

Tests. Node's own built-in test runner, zero dependencies, no npm install required:

npm test

The suite exercises the crypto round-trip, the wrong-passphrase and tampered-ciphertext failures, the room-code hashing, and a real end-to-end run where an in-process sender and receiver find each other over UDP and transfer over TCP.

Try the attacks. make attack runs only the adversarial/security suites and shows them reject: tampered-ciphertext and wrong-passphrase rejection, oversized-frame rejection, cross-origin 403, DNS-rebind 403, and garbage-datagram rejection.

make attack

Reproducible crypto-core demo (no LAN needed). make demo seals a secret under a passphrase and opens it back, then shows a wrong passphrase and a tampered ciphertext both fail loudly:

make demo

Benchmarks. make bench measures the scrypt passphrase-KDF time and AES-256-GCM seal/open throughput. Real numbers and a reproduce command are in BENCHMARKS.md.

Examples

examples/share-and-receive.mjs runs a real sender and receiver concurrently using shareEnv/receiveEnv directly — real UDP discovery, real TCP transfer, real encryption — and then demonstrates the honest wrong-passphrase failure:

node examples/share-and-receive.mjs

Real output from a local run (the room code is randomized each run, so that line will differ, and the peer address will be whatever local IP your machine has):

Room: example-a37e9214
Starting sender and receiver concurrently — real UDP discovery, real TCP transfer...

Sender result: { ok: true, peerAddress: '::ffff:192.168.1.7' }
Receiver result: { ok: true, envText: '63 chars', fromAddress: '192.168.1.7' }

Received text matches what was sent: true

Now trying with a WRONG passphrase — should fail loudly, not decrypt garbage:
Failed as expected: Could not decrypt the received data — wrong passphrase, or the payload was corrupted in transit.

Dependencies

Runtime dependencies: none. Pure Node standard library — nothing to install, no relay to run.

| | | |---|---| | Runtime dependencies | 0 — Node standard library only (dgram, net, crypto, http) | | Install to run | none — npx @strato-dan/array | | Install to test | none — npm test uses Node's built-in test runner | | Node | ≥ 18 | | Dev-only | husky — pulled in only if you clone to contribute; never needed to use the tool |

The UDP discovery and TCP transfer are Node's own dgram/net; the crypto is Node's own crypto. There is no dependency tree to resolve and nothing phones home.

Project contents

Every file below is the basic (open-source) tier only — there is no advanced/encrypted-tier code anywhere in this repository; see the section above for that boundary.

| Path | What it is | |---|---| | bin/dan-oss-array.js | The real CLI entry point — starts the local UI server. | | src/server.js | The loopback-only HTTP server serving the sender/receiver UI. | | src/crypto.js | Generic AES-256-GCM encrypt/decrypt + scrypt key derivation. Basic tier only. | | src/discovery.js | Real UDP broadcast announce/listen — room-code-hash based peer discovery. | | src/peer.js | The real one-shot TCP listener/connect used for the actual file transfer. | | src/sync.js | shareEnv/receiveEnv — orchestrates discovery + transfer + crypto together. | | public/ | The plain HTML/CSS/vanilla-JS sender/receiver UI. | | examples/ | Runnable example code using the library functions directly, no UI. | | test/ | Real unit + integration tests (npm test) — crypto round-trips and a real UDP+TCP sender/receiver run. |

FAQ

Can I send more than one file, or a whole directory? Not yet — shareEnv/receiveEnv moves one block of text (typically a .env file's contents). Multi-file transfer is a real possible future addition, not built here.

What happens if the receiver isn't listening yet when the sender starts broadcasting? startAnnouncing keeps re-broadcasting on an interval until a peer connects or the sender's own timeout elapses — order doesn't matter, but both sides do need to start within the timeout window of each other (120s sender / 30s receiver by default).

Does this work across Wi-Fi and Ethernet on the same LAN? Yes, as long as both interfaces are on the same broadcast domain — UDP broadcast discovery doesn't care about the physical link type, only the network segment.

Can it cross a NAT or the public internet? No — see "Honest limits" above. That would require a relay server, which is exactly the single point of failure this tool exists to avoid.

Contributing

See CONTRIBUTING.md for how to file an issue or submit a PR. Maintainers may use AI tools to help review contributions — please don't include personal information in an issue, PR, or commit beyond what's needed to describe the change.

Releasing

See RELEASING.md — the same version-bump/tag/publish process applies to every DAN-OSS tool, this one included.

License

MIT (code) — see LICENSE. The "DAN" name and logo are trademarked — see TRADEMARK.md.


[DAN] MEMORY SMASH — the full codebase-memory engine, and the home of [DAN] ARRAY's advanced encrypted tier — is coming soon.