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

@particle-academy/fancy-connector-core

v0.3.1

Published

The runtime under every Fancy connector: modes and estates, connections, one call path, a failure taxonomy that separates "it never arrived" from "nobody can tell", deterministic fakers, webhook verification, pure versioned rendering, declared metric shap

Readme

fancy-connector-core

The runtime under every Fancy connector. Modes and estates, connections, one call path, a failure taxonomy that knows the difference between it never arrived and nobody can tell, deterministic fakers, webhook verification, pure versioned rendering, chain posting, declared metric shapes, credential-free probes, and API-drift reporting.

Matched TypeScript + PHP, one repository, zero runtime dependencies in either ecosystem.

npm install @particle-academy/fancy-connector-core
composer require particle-academy/fancy-connector-core

It owns the wire. It never owns a gate.

Approval, liveness, the approved-bytes comparison, consent, second review and every journal belong to the host — because each is enforced in one place and every connector inherits it from the host's dispatch path rather than implementing it.

await connector.call(target, { dryRun, credentials });
//                              ^^^^^^  ^^^^^^^^^^^
//                              yours   yours

Three of those promises are tests, not intentions:

  1. Nothing here reads the environment. No process.env, no getenv. Your credential storage discipline — a gitignored file behind a whitelist, a secret manager, Laravel config — stays yours, because the package cannot reach past it.
  2. Nothing here contacts a URL of its own. No telemetry, no phone-home, no default endpoint. Even the drift checker does not fetch: you fetch, and pass the document in.
  3. Nothing here retries an ambiguous failure unless the connector declared that repeating a request is harmless.

The one that matters: retry, without ever sending twice

A network hiccup should not lose a call. A retry after a request that succeeded and whose response was lost is a double write — the exact failure an idempotency gate exists to prevent, arriving through the door marked reliability.

Nearly every retry helper reconciles those the same way and loses: it catches an error, waits, and tries again, because from the caller's side all failures look alike.

| what happened | did the provider receive it? | retry? | |---|---|---| | DNS failure, connection refused | no | always safe | | HTTP 429 / 5xx | yes, and it explicitly refused | safe — it says it did nothing | | timeout, abort, anything unrecognised | unknown | only where the connector is idempotent | | other 4xx | yes, and the answer was a real no | never |

import { classifyError, shouldRetry } from "@particle-academy/fancy-connector-core";

shouldRetry(classifyError(err).kind, { idempotent: connector.delivery.idempotent });

idempotent defaults to false, and delivery.why must cite the mechanism — Idempotency-Key, or the absence of one — because idempotent: true is the one claim whose failure is a public duplicate.


Text, and two one-line bugs that ASCII hides

import { measure, linkRanges, sliceByteRange } from "@particle-academy/fancy-connector-core";

measure("👍", "graphemes");   // 1   — "👍".length is 2
linkRanges("👍 https://example.test");  // UTF-8 BYTE ranges, not char offsets

ByteRange is a type, producible only by a function that encoded the string. A character-offset implementation is correct for ASCII and silently corrupts the link on any post containing an emoji — the post looks fine and goes somewhere wrong.


Rendering: pure, versioned, honest about loss

const payload = render(copy, {
  limit: 300, unit: "graphemes", thread: true, links: true, label: "Bluesky",
});

payload.segments;  // one entry per message; more than one means a thread
payload.problems;  // what could NOT be fitted. Never silently applied.
await payloadHash(payload);  // RENDERER_VERSION is INSIDE the hash

Show the payload before you approve it, recompute it at dispatch, refuse on mismatch. That is the only way "what was approved is what was sent" survives the existence of adaptation — and the renderer version being inside the hash is what stops it being checked separately and forgotten.


Threading

await postChain(payload.segments.map((s) => s.text), answering, post);

Root fixed at the top of the chain; parent advancing to whatever was just posted. Reverse them and every message attaches to the first — a fan, not a thread — and the provider's response looks identical either way. The post function is an argument so that is reachable by a test.


Probes: an auth error proves the transport

A connector written from documentation can be wrong in three ways that look identical until a credential arrives: the URL is wrong, the request shape is wrong, or the error handling never runs. All three are invisible to a fake server, because a fake server agrees with whatever your code does.

So call the real API with a deliberately invalid credential and require an auth-shaped refusal.

  • authStatuses is declared per provider — a Discord webhook answers 404 for an unknown id, so 404 IS its auth answer.
  • A 2xx is a failure. The credential is reaching nothing.
  • Offline is skip, never fail. A check that goes red on a train gets ignored, and is then worth nothing when it goes red for real.

Drift: it reports, it never adapts

A connector's worst failure is silent — the provider changes its API and nothing says so until something breaks.

And the fix is not a connector that reshapes itself. That connector cannot be reviewed, its behaviour depends on when it ran, and adaptation is only ever a guess at intent. So:

Drift reports. The provider decides. A person acts.

Drift also never changes runtime behaviour: it runs out of band, and a check that failed a working call because a document changed would be a self-inflicted outage.

What is checked is a narrow projection, not a diff — for the operations this connector actually calls, do the path, method, sent fields and read fields still exist? Where a provider publishes no spec (most do not), the fallback is a recorded shape: field names only.

outcome is clean | drifted | unchecked. The third is never collapsed into the first — a checker that could not see is not a checker that saw nothing wrong.


Depend on this with an open range, not a caret

// package.json
"@particle-academy/fancy-connector-core": ">=0.2.0 <2.0.0"
// composer.json
"particle-academy/fancy-connector-core": ">=0.2.0 <2.0.0"

Not ^0.2.0. A caret on a 0.x locks the MINOR — npm and Composer both read ^0.2.0 as >=0.2.0 <0.3.0 — so the next release is out of range and npm update reports success having installed nothing. A resolver quietly keeping the old version is indistinguishable from a resolver that had nothing to do, which is why this is worth stating rather than leaving to convention.

This package intends the open range: pre-1.0 minors may change what a connector sees, and CONNECTOR_API_VERSION is what tells you when — loudly, at registration, naming which side is behind. That is a stronger guarantee than a caret gives you, and it is the reason the caret is not needed here.

The first consumer of this package pinned ^0.1.0 and would have missed 0.2.0 entirely. That is the whole argument.

Documentation

  • AGENTS.md — the invariants, the traps, and what a change here breaks.
  • .ai/plans/fancy-connectors.md in the envelope — the architecture, the Socialite seam, the drift research, and every decision with its reason.

MIT.