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

@feedmepos/mf-media

v2.0.7

Published

Readme

media-portal

Vue 3 microfrontend, published as @feedmepos/mf-media and mounted into the portal shell (mf-portal-root) via import map at /media. Two tabs:

| Route | View | What it is | |---|---|---| | /library | views/AssetLibrary.vue | the asset centre — upload, tag, search, delete | | /studio | views/AiStudio.vue | the AI image studio — compose from a prompt |

The tab bar lives in App.vue because it is this module's own chrome, and App.vue is what app.ts exports as FmApp for the shell to mount. The active tab is derived from the route, so a deep link, the back button and a click cannot disagree.

Running it

pnpm dev          # standalone dev server on :5190
pnpm type-check
pnpm test         # node --test over test/*.test.ts
pnpm build:mf     # the published artifact

Standalone dev still requires a real portal sign-in: the studio reads coreStore.currentBusiness, so without a session there is no businessId and nothing can be generated. src/main.ts points at the local Go backend per .env.development.

To exercise the studio you need the backend too, and with no GEMINI_API_KEY it uses the Stub, which renders proportioned placeholders for free:

cd ../media-backend && GOTOOLCHAIN=go1.23.9 go run .

What verification here actually covers

Three gaps are worth knowing, because each one silently passes work that is wrong:

  • pnpm lint does not run. There is no ESLint config anywhere in this repo, so ESLint 8 parses every file as ES5 and fails on the first import — about 20 errors on a clean checkout, in files no feature touches. Not a gate; fixing it is separate work.
  • pnpm type-check does not check Fm* component props. <FmButton size="not-a-real-size"> passes clean. Read the component's own .d.ts under node_modules/@feedmepos/ui-library/dist/components/ before using a prop. Things a guess gets wrong: FmButton.size is 'md' | 'lg' with no 'sm', its icon prop is deprecated in favour of prependIcon, FmCircularProgress.size starts at 'md', and FmChip selection is selected + selectable.
  • pnpm type-check does not check anything from @feedmepos/media-picker either. That package's exports.types points at a dist/index.d.ts its build never emits, so the whole module resolves as any. And because the portal resolves it through the built dist rather than source, any change to media-picker needs pnpm picker:build from the repo root before the dev server or a build can see it.

So pnpm build:mf and the browser are the only real checks on a template. Note that build:mf only compiles reachable modules — a component nothing imports yet is not being verified by it.

Spacing numbers are px, and the scale is sparse

The design system's Tailwind plugin sets theme.extend.spacing to a px-valued scale:

0 4 8 12 16 24 32 40 48 56 64 72 80 88 96 104 112 120

It arrives through extend, not as a replacement, so a number not on that list silently falls through to Tailwind's own rem scale and lands about four times too large. gap-20 is not 20px, it is 80px. h-36 is 144px. w-44 is 176px.

This cost real time: an 80px-padded 320px panel left ~160px of content, split into two columns, which wrapped every label to one character per line. Nothing warns — the classes are real Tailwind, just not the values the design intends. When translating a mock's pixel values, check each number against the list above.

Arbitrary values (w-[320px], bg-[--fm-color-brand-primary,#FF7823]) do work and are the established idiom here — see AssetGrid.vue. Use them for anything off-scale.

Studio state survives a tab switch

The batches live in stores/generation.ts, not in AiStudio.vue's setup, so leaving for the asset centre and coming back does not throw away the run. The poll loop is deliberately not stopped on unmount: a batch generating while the merchant looks at the library should be finished when they return, not frozen where they left it.

Read it with storeToRefs, never plain destructuring — a Pinia store is a reactive proxy, and pulling batches straight out hands the template a snapshot that never updates.

Layout

src/
  App.vue                        the tab bar over <RouterView>
  router/shared.ts               both routes, each permission-wrapped
  views/AssetLibrary.vue         asset centre
  views/AiStudio.vue             studio page — layout only, no logic
  composables/
    generationState.ts           pure state transitions (tested)
    useGeneration.ts             reactive shell: refs, poll timer, network
  components/studio/             the studio's five components
  api/generation.ts              the three studio endpoints
  locales/*.json                 7 locales, identical key sets
test/
  generationState.test.ts        node --test, no vitest

generationState.ts is split from useGeneration.ts so the transitions with edge cases can be tested without Vue — the same division packages/media-picker draws between variants.ts and useAssetVariants.ts. The saved-preserving merge is the reason it earns its keep: a poll landing a second after a save would otherwise flip the button back to "save", which nobody would reproduce by clicking around.