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

@supacloud/query

v0.6.0

Published

TanStack Query adapter for SupaCloud procedure client with explicit invalidation tags

Downloads

1,815

Readme

@supacloud/query

Typed, grouped TanStack Query options for compiler-generated SupaCloud clients. Requires a regenerated client exposing procedureClient. Existing REST methods, API_PROCEDURES, and client.procedures metadata remain unchanged.

import { createQueryAdapter } from "@supacloud/query";
import { createSupaCloudProcedureClient } from "@supacloud/js";
import { createApiClient } from "./generated/client";

const client = createSupaCloudProcedureClient({
  supabase,
  functionName: "application",
  generated: createApiClient,
});
const api = createQueryAdapter(client, {
  keyPrefix: [projectRef, tenantId, userId],
  queryClient,
});
const detail = api.items.detail.queryOptions(
  { params: { id: "item-1" } },
  { tags: ["items"] },
);
const mutation = api.items.accept.mutationOptions({
  invalidateTags: ["items"],
});
await mutation.mutationFn({
  input: { params: { id: "item-1" } },
  execution: { idempotencyKey: "attempt-1" },
});

Generated clients can carry explicit route and Feature Slice cache metadata. When present, query options use the generated route tags by default and mutation success uses the Feature transition invalidateTags by default. Passing tags or invalidateTags remains an explicit per-call override; no tags are inferred from controller or procedure names.

Inputs retain explicit params, query, body, headers, and cookie sections. Required parameters and idempotency keys are checked by TypeScript. No flat-input guessing, Supabase private-field inspection, or automatic mutation retry is performed. Supabase auth/refresh and Functions transport remain owned by createSupaCloudProcedureClient.

Recreate the adapter when project, tenant, or actor changes. Query keys snapshot JSON inputs; mutation keys never contain execution keys. Cancellation is propagated without claiming that a cancelled write rolled back. Tags are explicit and adapter invalidation is limited to its identity prefix. A custom success callback does not disable configured invalidation.

The SDK also accepts apiClient in createSupaCloudClient, or sdk.withClient(client). Both preserve inferred procedure types and expose queryAdapter({ keyPrefix, queryClient }).

Imperative Reads With Domain Contracts

Use fetchQueryResult for loaders that need a Promise rather than a component query subscription. It reuses the existing QueryClient; do not create a second cache or maintain a separate shared-request consumer counter.

import { fetchQueryResult } from "@supacloud/query";

const item = await fetchQueryResult(
  queryClient,
  api.items.detail.queryOptions({ params: { id: "item-1" } }),
  {
    decode: decodeItem,
    signal,
    staleTime: 10_000,
  },
);

decodeItem is the application's existing synchronous or asynchronous runtime decoder. Its return type determines item; the helper requires a decoder and does not supply an unchecked result-type override. Generated transport validation still runs before the raw result is cached. The additional domain decoder runs for every caller, including cache hits. Only raw transport results are shared: one caller's narrower contract failure does not evict or poison another caller's valid data. Do not mutate the raw value inside a decoder.

Cancelling one caller rejects only that caller. When the last native query observer leaves, TanStack cancels the transport and ignores its late response. Other mounted query observers retain ownership. Cancellable imperative callers sharing a key should all use this helper: bare QueryClient.fetchQuery calls do not register observers. No read retry is added, even when client defaults retry. Domain decoder errors and transport errors retain their original identity; query cancellation is reported as AbortError.

  • refresh: true cancels the previous exact-key fetch, marks its cache stale, and fetches a new snapshot. Superseded callers receive cancellation, not a successful stale value. Other identities and keys are untouched.
  • cache: "none" bypasses both cache reads and writes for passwords, signed download credentials or other sensitive results. Calls are not deduplicated.
  • Pass a component/target lifetime signal to stop obsolete consumers. Cancellation does not revoke a result already returned or prove that a write rolled back. This helper accepts query options, not mutations.

This replaces generic read execution glue, not application authorization, business schemas, command receipts, task polling or the FA repository itself.

Acceptance

Scenario: A cache hit cannot bypass a caller's contract
  Given one shared raw response and two different domain decoders
  When both callers read the same query
  Then each decoder runs and only the incompatible caller fails

Scenario: Cancellation belongs to a consumer
  Given two consumers share a pending query
  When one consumer cancels
  Then the other can finish and the cancelled consumer does not decode

Scenario: Refresh supersedes an old response
  Given a pending query that ignores cancellation
  When another caller explicitly refreshes and receives a new response
  Then the old response cannot replace the refreshed cache

Scenario: Sensitive reads bypass the cache
  Given a cached response for the same key
  When a caller selects cache none
  Then it reads the transport and does not change the shared cache