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

@ai-matrx/data

v0.18.0

Published

The opinionated AI Matrx data layer: the /db tier's hard-won Supabase primitives — optimistic concurrency, complete-list reads, JSONB merge, session-retry, the domain-wide auth cookie, realtime channel hygiene — the /net resilience trio, and the /files la

Readme

@ai-matrx/data

The opinionated AI Matrx data layer: the /db tier — the hard-won Supabase primitives every Matrx client uses against the platform database — the /net tier — the resilience trio every outbound call and event stream rides — and the /files tier — the Matrx file-communication client. Each primitive exists because a real production incident forged it; the file headers carry the stories.

npm install @ai-matrx/data

| Subpath | What it carries | |---|---| | @ai-matrx/data | Core: structural PostgREST types, pgErrorToError, the credentials port, plus the /net trio re-exported (it rides the core). | | @ai-matrx/data/db | The Supabase lane: optimistic concurrency, complete-list reads, JSONB merge, session-retry, auth cookie, realtime hygiene. | | @ai-matrx/data/net | The net-resilience trio: resilient fetch, retry/backoff, stream stall watchdog, structured NetError vocabulary. | | @ai-matrx/data/files | The file lane: durable-ref resolution, the mx_files_session bootstrap, authenticated blob fetch with dedup, uploads, the public-link door, typed unavailable states. | | @ai-matrx/data/next | The Next.js binding: ONE factory for every Supabase client a Next app builds — browser, Server Component, Route Handler, proxy/middleware, OAuth callback — plus the whole middleware auth-cookie pass. | | @ai-matrx/data/react | The React bindings: useAsyncData, useRealtimeChannel / useRealtimeQuery, useAsyncAction. Stamped "use client". |

@ai-matrx/data/db

| Export | What it does | |---|---| | guardedUpdate | Optimistic concurrency as compare-and-swap on the canonical version column. Classifies "0 rows updated" honestly: conflict (with the current row so the UI can offer merge/refresh) vs not_found. Callback-shaped — it never needs to know your schema or client. | | readAllRows / tryReadAllRows | The ONE way to read a list you intend to treat as complete. PostgREST silently caps responses (HTTP 206 looks like success); a truncated list used for an existence/diff decision is a confidently wrong answer. Pages to the server-declared total and throws (IncompleteReadError) rather than return a provably partial list. readAllRowsRest / tryReadAllRowsRest are raw-fetch twins for scripts with no client. | | mergeJsonColumn | Merge into a row's JSONB column without losing a concurrent writer's keys: composes guardedUpdate with a bounded re-read-and-remerge retry. Returns a typed status, never throws for a normal outcome. | | createSessionRetry | Recovers the one failure worth retrying: a request that reached PostgREST with no user JWT while a session actually exists (refresh in flight, cookie swap). Retries exactly that cause, exactly once, after re-resolving the session. Everything else passes through untouched. | | createOAuthRefreshFetch | Keeps auth-js's normal storage, locking, refresh lifecycle and events, but routes a proven allowlisted OAuth-client session's refresh to /auth/v1/oauth/token with its JWT client_id. Normal sessions continue through Supabase's ordinary refresh endpoint. | | createAuthCookie | One login across every subdomain of your apex: a renamed (sb-matrx-auth), domain-wide auth cookie issued only on real apex hosts — localhost and previews get host-only, because a browser silently rejects a mismatched Domain. | | createActiveOrgCookie | ONE browser memory of the organization a person is acting in, shared by every Matrx surface on the apex (matrx-active-org, Domain=.aimatrx.com): identity-keyed (<userId>:<orgId>), domain-wide only on a listed apex, host-only elsewhere. Stores the stored-selection rung of the canonical order; never decides. | | uniqueChannelTopic | Realtime channel hygiene: unique per-mount topics so React 19 double-invoked effects and Fast Refresh can never collide with a still-joined channel. |

@ai-matrx/data/net

| Export | What it does | |---|---| | resilientFetch | fetch with a two-stage timeout — connect (default 15s, request start → headers) and total (default 120s, null disables) — plus a composed AbortController returned to the caller for cancelling body reads. Never pre-blocks on navigator.onLine (the flag is a hint; a real outage taught us it lies) — offline is only reported when a genuine network failure corroborates it. | | withRetry | Exponential backoff with jitter for idempotent operations only. Default predicate retries exactly what the error taxonomy marks retryable (connect timeouts, network failures, HTTP 408/429/5xx). Honors an AbortSignal mid-backoff; never wrap user-authored submissions. | | monitorStream | Wraps an async event iterable with two guarantees: a heartbeat deadline (default 30s between events) and an absolute lifetime ceiling (default 10min). A stuck stream throws HeartbeatTimeoutError/TotalTimeoutError — and aborts your AbortController — instead of awaiting forever. | | NetError family | ConnectTimeoutError, TotalTimeoutError, HeartbeatTimeoutError, NetworkError, HttpError, AbortedError, OfflineError — every failure resolves to a class with a code and an honest retryable flag, so callers branch on type, never on string matching. Helpers: isNetError, toNetError, isTransportFailure (is this the transport dying, or the server answering? — decides how LOUD to log), extractErrorMessage. |

Wiring: there is nothing to inject. The tier has zero dependencies and zero seams — fetch and timers come from the environment (Node 20+, browsers, React Native/Hermes), and it never touches Supabase, org context, or the API lane. Pass your own AbortSignal to resilientFetch/withRetry and your own AbortController to monitorStream so a watchdog timeout also cancels the underlying request. Everything here is also re-exported from the root @ai-matrx/data entry point.

@ai-matrx/data/files

The client SDK for the AI Matrx file contract — the communication half of the media seam. One factory builds the whole lane:

import { createMatrxFilesClient } from "@ai-matrx/data/files";

const filesClient = createMatrxFilesClient({
  credentials,                                  // the core CredentialsPort
  filesBaseUrl: () => resolveFilesBaseUrl(),    // your backend base (value or resolver)
  // everything else has a shipped default: origins, diagnostics, fetch,
  // metadata source (GET /files/{id} cache), in-memory blob cache.
});

The result structurally satisfies @ai-matrx/media's MediaClient port — construct with the media brand (createMatrxFilesClient<DurableSrc>(…)) and hand it to the media provider; the compiler checks the port, no cast.

| Export | What it does | |---|---| | createMatrxFilesClient | The client: resolve (file_id → durable URL + the transport decision: permanent CDN for public files, bearer-authenticated blob lane for private pixels, cookie-authenticated element bind for video/audio), getBlob (in-flight dedup + LRU byte cache), recoverLoadError (the ONE retry policy: session refresh → same-URL retry, second failure terminal), upload/uploadMany (buffered multipart to POST /files/upload, idempotency-keyed, XHR byte progress), shareableUrl (THE public-link door: permanent CDN or reuse-or-mint a no-expiry read-only share link, on click, fails closed), shareableUrlNoMint (the COPY twin — never mints), classifyError (typed access_denied/not_found/deleted render-as-state), ensureSession. | | createFilesSession | The mx_files_session HttpOnly cookie bootstrap on every byte-serving base (cookies are per-host) — deduped, freshness-margined, non-fatal, never throws. | | createFileUrlRecognizer | "Is this URL one of OUR files?" with the origin list injected as a value (Matrx defaults shipped): byte-endpoint URLs promote to their file_id, legacy signed bucket URLs recover their identity, CDN URLs are detected. | | classifyMediaUrl / shareableMediaUrl / isSignedUrl | The ONE signed/expiring-URL classifier (both AWS dialects + revocable share byte endpoints). resolve refuses an expiring URL — screams through the diagnostics sink, then throws: a signed URL is a handoff, never an identity. | | fileUrls / shareUrl | The one durable-URL contract: {base}/files/{id}/download (?inline=1) and {base}/share/{token} — the exact spellings the backend emits. | | Error taxonomy | FileAccessDeniedError (a proven 403 — never retried), FileNotFoundError, FileDeletedError, ShareLinkInvalidError, ExternalFetchError, FileUploadError; classifyUnavailable also classifies structurally by code. |

Transport policy: resolveUploadTransport picks resumable for files ≥ 80 MB (TUS_TRANSPORT_THRESHOLD_BYTES). This version ships the buffered multipart transport; for larger files inject largeUploadTransport (your resumable lane) — without it the client refuses loudly instead of attempting an upload that would fail at the edge.

Ports with defaults: metadata (FileMetadataPort, default: cached GET /files/{id}), byte cache (BlobCachePort, default: 250 MB in-memory LRU that owns its object URLs), diagnostics sink, injected fetch. React Native hosts set attachAuthHeadersToResolution: true so private resolutions carry { uri, headers: { Authorization } } — there is no cookie lane on native; call client.primeAuth() at boot.

@ai-matrx/data/next

A Next.js app has FIVE places that must construct a Supabase client, and every one of them must pass the SAME auth-cookie options or it cannot see the session the others wrote. One factory owns all five. The host injects IDENTITY only.

// One module in your app — everything else imports from here.
import { createNextSupabase } from "@ai-matrx/data/next";
import type { Database } from "@/types/database.types";

export const supabaseNext = createNextSupabase<Database>({
  // STATIC member accesses: Next only inlines NEXT_PUBLIC_* for those.
  supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,
  publishableKey: process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY,
  apexDomain: "example.com",
  cookieName: "sb-example-auth-v2",
  legacyCookieName: "sb-example-auth", // optional: migrate + clear an old key
});

| Door | Call | |---|---| | Client Component | supabaseNext.browserClient() — a singleton on a globalThis slot | | Server Component / Action | supabaseNext.serverClient({ cookieStore: await cookies(), host }) | | Route Handler | supabaseNext.routeClient({ requestCookies: request.cookies, setCookie, host }) | | Proxy / middleware | await supabaseNext.middlewareSession({ host, requestCookies, createResponse, createRedirect }) |

middlewareSession is the whole auth pass in one call and returns { user, client, response, redirect(url), splitCookieJar, ambiguousAuthCookies, authUnavailable }. It owns: legacy-key migration (absent-only, so a live session is never overwritten), the "nothing may run between createServerClient and the identity resolve" rule made structural, persisting a migrated session under the current key, clearing the superseded key at the scope this host issued it on, no-store response headers on any cookie-bearing response, and cookie carry-over onto redirects. Dropping any one of those logs users out at random — which is how each was found.

The identity resolve is getClaims(), never getUser(), and it is BOUNDED. getUser() sends a request to the Auth server for every JWT; getClaims() verifies the access token against the project's JWKS with WebCrypto — locally, usually with no network call, and just as trusted, because the signature is checked. It needs an asymmetric signing key on the project (ECC/RSA); with a symmetric secret it degrades to a getUser()-shaped request per call, still correct but with none of the saving. A 2.5s identity budget — ONE deadline per request across /auth/v1/user, a token refresh and the JWKS fetch, after which auth-js is answered with a non-retryable 408 so its 30s refresh backoff cannot run (0.18.0) — means a stalled auth server costs one request its identity instead of costing the page its response — on Vercel, where Next 16 forces this pass into a Node Lambda with a hard task cap, the unbounded version returned 504 MIDDLEWARE_INVOCATION_TIMEOUT to real people.

🚨 authUnavailable is the consumer's obligation. It means the authority could not be REACHED, which is NOT "signed out": user is null, but no auth cookie was written, expired or healed and the superseded key was not cleared. Read it before treating user === null as signed out — a host that bounces to /login on a null user must skip that bounce when the flag is set, or a 2.5s network blink signs people out mid-session. A call site needing created_at, identities, last_sign_in_at, factors or *_confirmed_at must keep getUser() elsewhere: the JWT carries none of them. Full contract: common-docs/systems/platform/proxy-identity/FEATURE.md.

No next/* import lives in the package. cookies() and NextResponse arrive through structural seams (createResponse: () => NextResponse.next({ request })), so /next builds and tests outside Next and never drags the framework into another consumer's graph. Missing identity throws MissingSupabaseIdentityError NAMING the variable, instead of the cryptic undefined.trim() TypeError that process.env.X! produces from inside Supabase.

@ai-matrx/data/react

Three hooks, each built at a MEASURED repeated consumer — not a data-fetching framework. There is no cache, no store and no query client here: these compose under your Redux or React Query, they do not compete with it. What they own is the part every hand-rolled copy gets wrong.

| Hook | What it owns | |---|---| | useAsyncData(load, deps, opts) | Cancellation (a real AbortSignal reaches your loader), stale-response ordering, honest error conversion (a PostgREST error is a plain object — String(err) renders "[object Object]"), retry of TRANSPORT failures only, keepPreviousData so a key change never blanks the screen, and an abort that is silent because it is not a failure. | | useRealtimeChannel(client, topic, bindings, opts) | Unique per-mount topics, reconnect with exponential backoff and a stability reset, an onReconnect catch-up door (events missed while the socket was down are GONE), honest connecting/connected/reconnecting/disconnected status, latest-callback refs, guaranteed teardown. | | useRealtimeQuery({ client, topic, watch, load, deps }, opts) | The two composed, with realtime events COALESCED so a bulk write is one read, and a re-read wired to reconnect. | | useAsyncAction(action, opts) | Double-submit REFUSAL (a disabled button is not a guard), unmount-safe state, honest errors, and a discriminated { ok: true, value } \| { ok: false, error } result so nothing is swallowed. Writes are never retried — a replayed submission is how you get two invoices. | | usePaginatedData({ queryKey, initialCursor, loadPage, getRowId }) | Cursor accumulation with one request at a time, identity masking, abort/stale-result handling, explicit retry, in-place row-id updates, and loud repeated-cursor refusal. It has no cache and no table dependency. |

const { data, loading, error, refresh, realtimeStatus } = useRealtimeQuery({
  client: supabaseNext.browserClient(),
  topic: `jobs:${fileId}`,
  watch: [{ schema: "docproc", table: "jobs", filter: `file_id=eq.${fileId}` }],
  load: ({ signal }) => listJobsForFile(fileId, signal),
  deps: [fileId],
}, { enabled: fileId !== null });

The Supabase client type is STRUCTURAL — the package never imports @supabase/supabase-js. A real client satisfies it by shape, and there is a compile-time proof of that in the package's own tests (it caught a too-narrow signature during this package's build, which is exactly the failure a host would otherwise have hit).

@ai-matrx/data (core)

Structural types (PostgrestLikeError, MaybeSingleResponse, Json) and pgErrorToError — PostgREST errors are plain objects, not Errors; this folds them into descriptive real errors. The /net trio is re-exported here as well.

Design

  • Zero runtime dependencies. All Supabase typing is structural — a real supabase-js client satisfies the shapes; nothing is imported from it. Works in Node 20+, browsers, and React Native/Hermes.
  • Injected hosts, opinionated behavior. Values and clients come in through arguments (apexDomain, auth); the behavior — the CAS contract, the refusal to return partial lists, the single-cause retry — is deliberately non-configurable. The opinions are the product.
  • Dual loader. ESM and CommonJS conditions with matching declarations, proven from the packed tarball on every release.

MIT © AI Matrx