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/media

v0.6.6

Published

The AI Matrx media components kit: durable-ref-only renderers for images, video, audio and file thumbnails that just work with the Matrx file system — headless core hooks plus DOM bindings, wired to an injected MediaClient. A signed URL is a handoff, neve

Readme

@ai-matrx/media

Media components that just work with a durable file system. Renderers for images, video, audio and file thumbnails that take a durable reference — a file_id or a permanent public URL — and own the whole URL lifecycle: resolution, auth transport, load-error recovery, typed unavailable states, upload progress, and share/download/copy/open actions.

The package ships zero transport. Everything data-shaped arrives through one injected port, the MediaClient. That is the point: every media breakage we ever shipped came from code that hand-built a URL or an <img>; here the correct path is the only path the types allow.

@ai-matrx/media          types only — MediaRef, DurableSrc, MediaClient, host ports
@ai-matrx/media/core     headless React hooks (platform-free state machines)
@ai-matrx/media/react    DOM components (Tailwind classes, inlined SVG icons)
@ai-matrx/media/share    the complete share popover body (optional peer: @ai-matrx/associations)

The rules the types enforce

  1. The package never fetches a media URL itself. Bytes exist only via MediaClient.getBlob.
  2. Every component takes a ref, never a src. Even a caller-supplied URL string is classified by resolve(), never trusted.
  3. A signed URL is a handoff, never an identity. The only string a media element binds is the branded DurableSrc, which only a MediaClient implementation can mint. An expiring URL cannot pass the types without an unsafe cast.
  4. Share affordances fail closed. shareableUrl returns null rather than ever emitting a signed URL; unwired actions render disabled.
  5. One retry policy. Load errors route through MediaClient.recoverLoadError (session refresh → same-URL retry → terminal). The package has no retry logic of its own.

Quick start

import { MediaProvider } from "@ai-matrx/media/core";
import { InlineMediaRef, MediaThumbnail, MediaLightbox } from "@ai-matrx/media/react";

// `client` implements the MediaClient interface from "@ai-matrx/media".
// Matrx apps wire the canonical implementation from @ai-matrx/data/files;
// any structural implementation works.
<MediaProvider client={client} ports={{ ImageComponent, actions, playbackSession }}>
  <InlineMediaRef ref={{ file_id }} size="md" fit="cover" />
  <MediaThumbnail mediaRef={{ file_id }} fileName="report.pdf" />
</MediaProvider>

InlineMediaRef accepts a MediaRef ({ file_id, url?, mime_type? }), a bare fileId string, or an external public URL string — and renders a correctly-sized <img> / <video> / <audio> with fallback and informative error states. ref is a content prop (React 19); use mediaElementRef for DOM access.

Headless hooks (/core)

| Hook | What it owns | |---|---| | useMediaResolution(ref) | ref → MediaResolution as state (empty / ready / unavailable with a typed reason) | | useMediaLoadRecovery(src) | the retry-key/error machine over the client's ONE recovery policy | | useMediaBlob(ref) | object-URL bytes with lifecycle + release | | useMediaUpload() | single + batch upload, progress, and a per-file tray (entries) | | useThumbnailSource(ref, opts) | the 4-tier thumbnail decision (rendered thumb → variant → live source → icon) | | useMediaActions(ref) | share/download/copy/open availability + execution over the injected actions port | | getFileKindDetails(name, mime) | filename/MIME → category, icon name, color |

Components (/react)

InlineMediaRef · MediaThumbnail · FileIcon · FileUploadDropzone (+ UploadProgressList, useMediaDropzone) · MediaActionToolbar · MediaLightbox — plus the package's own inlined SVG icon set (no icon library dependency).

Actions & sharing

Hosts inject a MediaActionsPort (share, download, copy, open handlers and/or a rich SharePopover component). The toolbar and lightbox render whatever is wired and disable the rest — sharing integration plugs in without touching this package.

<MediaProvider client={client} ports={{ actions: { download, share, SharePopover } }}>
  <MediaActionToolbar mediaRef={{ file_id }} fileName="photo.png" />
</MediaProvider>

The complete share body (/share)

/share ships the popover BODY the slot was reserved for — the canonical Matrx share experience:

  • Copy public link — one click asks MediaClient.shareableUrl(ref) for the truly-permanent URL (the host's implementation reuses or mints a no-expiry share link, or returns the permanent CDN URL for public files) and copies it. null fails closed — never a signed URL.
  • External refs get the simplified surface: the safe external URL or a disabled row.
  • Manage all links / who-can-see-this are host slots (manageLinks callback, AccessSummary component) — link inventory and reachability live with the host's iam surfaces.
  • Linked to / Attach to… — the association affordances, riding @ai-matrx/associations through its public hooks. They light up when an AssociationsProvider is mounted above and degrade to absent when not.
import { createMediaSharePopover } from "@ai-matrx/media/share";

const SharePopover = createMediaSharePopover({
  manageLinks: (ctx) => openShareLinkDialog(ctx),   // optional
  AccessSummary,                                    // optional host panel
  notify: { success: toast.success, error: toast.error }, // optional
});

<MediaProvider client={client} ports={{ actions: { SharePopover, download, copy } }}>
  {/* every toolbar/lightbox now opens the full share experience */}
</MediaProvider>

Only /share imports @ai-matrx/associations — a REAL dependency, installed automatically (it brings @ai-matrx/design-system with it). Nothing extra to resolve; association affordances still degrade to absent at runtime when no AssociationsProvider wraps the tree. The other entries never touch it.

Diagnostics — a terminal failure is never silent

Every dead render (a refused resolve(), failed private-pixel bytes, a load error the ONE recovery retry couldn't fix, a failed session mint) emits exactly one strictly-typed MediaFailureInfo — phase, durable mediaRef identity (never a signed URL), status?, retryOutcome?, terminal, message — latched per media identity so re-renders never spam. Bind the sink to your error system:

The retry allowance advances only after React commits the retry-key remount; duplicate browser error events from the original element while the session refresh is in flight are ignored and never consume the real retry.

<MediaProvider
  client={client}
  ports={{ diagnostics: { capture: (info) => myErrorCapture(info) } }}
>

Without a bound sink the package console.errors the same payload — loud by default, never silent. If your MediaClient.recoverLoadError returns a MediaRecoveryReport carrying the session mint's secret_source: "ephemeral", the package immediately captures an app-wide warning that private renders will break across server restarts/instances.

File viewers (/viewers)

Full-pane rendering of ONE file — a preview pane, a file tab, a code editor's binary-file fallback. MediaFileViewer dispatches on the file kind and ships working bodies for text, code, SVG, HTML and unknown files.

import { MediaFileViewer } from "@ai-matrx/media/viewers";

<MediaFileViewer
  source={{ kind: "ref", ref: { file_id } }}
  fileName={file.name}
  fileSize={file.size}
  generic={{ onDownload }}
/>;

Kinds whose rendering IS a heavy browser-only engine — PDF, Markdown, spreadsheets, Office documents — are yours to register, so a consumer that only shows text files never carries a PDF engine:

import { registerMediaViewer, registerMediaCodeHighlighter } from "@ai-matrx/media/viewers";

registerMediaViewer("pdf", MyPdfViewer);          // gets MediaViewerProps
registerMediaCodeHighlighter(MyPrismHighlighter); // optional: colour for code

Until you register one, that kind renders an announcing default: it names the missing engine and the remedy and still offers download / view-as-text. It is never a blank pane. (Code is different: with no highlighter registered it renders complete — monospace, line-numbered, copyable — just without colour, so it announces nothing.)

Registering a kind the package already renders replaces the built-in, which is how you plug in a domain-specific viewer of your own.

The blob source lane ({ kind: "blob", blob, url }) renders bytes you already have without touching the MediaClient at all.

Next.js (/next)

The ImageComponent port, implemented over next/image so you never write that wrapper again. next is an optional peer — nothing installs it for you, and no other entry imports it.

import { NextMediaImage } from "@ai-matrx/media/next";

const ports: MediaHostPorts = { ImageComponent: NextMediaImage };
// or: createNextMediaImageComponent({ unoptimized: false, quality: 90 })

It defaults to unoptimized, which is correct for Matrx media: durable file URLs are session-cookie authenticated and Next's optimizer fetches them from the server, where there is no user session.

Styling

/react uses Tailwind utility classes with semantic tokens (bg-muted, text-destructive, …). Tailwind v4 hosts register the package as a source:

@source "../node_modules/@ai-matrx/media";

SSR / RSC

The root entry is server-safe (types + one pure function). /core, /react, /share, /viewers and /next are client modules ("use client" is stamped per entry). Nothing touches window at import time.

License

MIT. Inlined icon paths copied from Lucide (ISC).