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

wrapflow-app

v0.3.74

Published

Typed, browser-safe client runtime for released Wrapflow Apps.

Readme

wrapflow-app

The zero-dependency, browser-safe runtime used by generated Wrapflow App clients. It talks only to a released App's typed contract and never accepts a Wrapflow account API token.

npm install --save-exact --ignore-scripts 'wrapflow-app@<reviewed-version>'
npm install --save-dev --save-exact --ignore-scripts 'wrapflow@<reviewed-version>'
node ./node_modules/wrapflow/wf.mjs app client <app-id> --file src/wrapflow.generated.ts

Replace <reviewed-version> with one exact version whose registry metadata, advisories, provenance, license, package contents, and publish age you reviewed. Do not use a mutable tag such as latest; commit the resulting lockfile. Invoke the reviewed project-local CLI by its package path as shown above. Do not ask npx to resolve the wf binary: when the local dependency is absent, it can resolve the unrelated registry package named wf.

wrapflow-app is the browser runtime dependency. The separate wrapflow package provides the wf generation and operations CLI and is only needed on development or build machines. An MCP client can invoke the equivalent App client generation operation instead of installing the CLI directly.

Import the generated adapter in React, Angular, Vue, Tailwind, or plain TypeScript projects:

import { AppClient } from './wrapflow.generated'

async function main() {
  const app = await AppClient.connect({
    baseUrl: 'https://client-requests.wrapflow.app',
    getToken: async () => currentAppUserJwt(),
  })

  await app.assign_request.execute(
    { owner: '[email protected]' },
    {
      recordId: 'request-123',
      idempotencyKey: crypto.randomUUID(),
    },
  )

  const report = await app.run_report.invoke({ region: 'eu', limit: 5 })
  const active = await app.active_requests.query({ limit: 20 })
  document.querySelector<HTMLDivElement>('#app')!.textContent =
    JSON.stringify({ report, active }, null, 2)
}

void main()

In plain Vite projects, keep startup awaits inside an async entry function so the default production target builds without enabling top-level await.

The generated adapter pins the App Contract compatibility hash and imports this package for transport, authentication, version checks, and stable typed errors. Named filtered views are generated as typed query resources; their declared predicates are enforced by the App before any narrower caller filters. Workflow invocation uses the Contract-v2 { params } envelope and semantic media type internally; do not hand-write that transport. Do not put a Wrapflow account token in browser code.

Checkout uses that same typed transport. For anonymous idempotent checkout, persist the returned ownershipToken privately with the idempotency key and pass both after a reload; authenticated Apps obtain their App-user token from the configured token/getToken option. Capabilities are headers, never URL parameters or log fields.

Run an account-owner command on the uploaded draft

An uploaded page uses its generated client on the current App origin. Open the fresh signed draft link returned by the upload. This example's App has no hosted App-user sign-in configured and uses the owner's draft authority. The link itself carries its issuer's write authority: anyone holding it can exercise those writes without a Wrapflow account session. Protect the link as a credential; an account session alone does not authorize the draft host. The host supplies the preview authority after checking the link. Your page does not need an account API token or a second owner login. For an articles entity and a create-article create command with access: { audience: 'owner-only', responseFields: ['slug'] } and the four input fields below, generate the client from the owner's inspected Contract:

import { AppClient } from './wrapflow.generated'

async function createArticle(slug: string, title: string, body: string) {
  const app = await AppClient.connect({ baseUrl: window.location.origin })
  return app.create_article.execute(
    { slug, title, body, published: false },
    { idempotencyKey: crypto.randomUUID() },
  )
}

Call createArticle(slug, title, body) from your form handler and show the result or refused error. It saves a private article; a separate declared command would publish it. This example assumes the generated command getter is create_article; use the name your generated file actually declares. A caller without this owner draft authority cannot run the command. An App-user principal, even with a role named owner, cannot run an account-owner command.

Hosted App-user sign-in on an uploaded page

After the account owner approves hosted sign-in, inspect contract.authentication. For mode: 'hosted-email-code', bundle this helper with the generated client:

import { AppClient } from './wrapflow.generated'

async function startSignIn(email: string) {
  const app = await AppClient.connect({ baseUrl: window.location.origin })
  await app.auth.requestCode(email)
  return async function finishSignIn(code: string) {
    await app.auth.verifyCode(email, code)
    return app
  }
}

On the Send code action, call startSignIn(emailFromForm) and retain the returned finishSignIn. When the person enters the emailed code, call finishSignIn(codeFromForm) and reuse its returned app for queries and commands. The client retains the App-user token and attaches it to subsequent calls; do not construct auth routes or bearer headers. Keep the code-entry UI and error state in your page. The emailed code needs a real mailbox; draft test users rehearse roles without accessing anyone's email.

Live account-owner boundary: this signs an App user in. It supports commands granted to that user's App roles through allowedRoles; it does not establish Wrapflow account ownership for access.audience: 'owner-only'. Account-owner commands require the owner's Wrapflow account authority and are omitted from the live public Contract. There is no generated-client browser account-owner sign-in method. Use the owner draft path above for that example; do not copy an account API token into the page or silently weaken its command policy. An App with no authentication has no app.auth sign-in capability.

Read one article with its long text

For an articles entity with a unique slug key and a body text field declared with maxLength: 500000, use a declared Flow filter view named Published articles with the expression published == true directly after the articles table. In exported flow text, the filter clause is let published_articles = filter(input: articles, where: published == true); keep the saved label/metadata and inspect the resulting Contract resource name. Generate its client; this example assumes its getter is published_articles. This view accepts narrower queries while its published-only filter stays on the server. The Contract must make slug, title and body readable.

Put <article id="article"></article> in your page. In its bundled TypeScript, load one article by its short key and select the whole body explicitly:

import { AppClient } from './wrapflow.generated'

async function loadArticle(slug: string) {
  const app = await AppClient.connect({ baseUrl: window.location.origin })
  const { items } = await app.published_articles.query({
    where: [{ field: 'slug', op: 'eq', value: slug }],
    select: ['slug', 'title', 'body'],
    limit: 1,
  })
  const article = items[0]
  if (!article) throw new Error('Article not found.')
  document.querySelector<HTMLElement>('#article')!.textContent = article.body
}

Call loadArticle('first') from your page's async startup or click handler and show any rejected error to the reader. On an uploaded page, the current origin addresses its draft or released backend. For a separately hosted frontend, replace it with the Wrapflow App's backend URL.

Lists omit long text unless select names it; the response reports omittedFields. limit: 1 alone does not include it. Filter on the unique short key, never on the long body (long text cannot be filtered, sorted, searched or grouped). No matching visible row means missing or unpublished; handle that state without reading the private table. A fixed view created with define kind:"view" instead accepts only ordering, paging and counting: do not send it where or select, or assume it accepts a slug parameter. Inspect the Contract and verify the draft before choosing the read resource. If your inspected Contract exposes an entity query, query({ recordId, select: ['body'] }) also reads one record; use the declared resource rather than inventing a route.

Hosted single-file Wrapflow Apps already receive the matching same-origin runtime and do not need this package.