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

@flow-industries/id

v0.24.2

Published

Passkey-first identity for Flow applications. One passkey bound to `id.flow.industries`, usable across Flow apps with audience-bound JWTs and optional Tempo signing.

Readme

Flow ID

Passkey-first identity for Flow applications. One passkey bound to id.flow.industries, usable across Flow apps with audience-bound JWTs and optional Tempo signing.

Develop

cp .env.example .env
bun install
bun run dev

bun run dev is the only supported local application launcher. It starts the API, dialog, playground, and landing page on the first free block of four consecutive ports. Configure DATABASE_URL and BETTER_AUTH_SECRET in .env first.

The launcher validates locally stored JWT signing keys before starting Auth. If BETTER_AUTH_SECRET changed, only keys that can no longer be decrypted are rotated so local session creation keeps working after environment changes. It also refuses to start when migrations fail instead of serving against a partially migrated schema.

AT Protocol identity

Bluesky and other AT Protocol accounts can sign in to Flow ID or connect to an existing account. Flow user IDs remain stable; the provider DID identifies the connection. New accounts do not need an email, passkey, or wallet to enroll.

Set ATPROTO_PUBLIC_URL, ATPROTO_PRIVATE_KEY (an ES256 private JWK with a stable kid), and ATPROTO_STORAGE_KEY (a base64-encoded 32-byte encryption key) to enable the integration. Leave all three unset to disable it. Production uses HTTPS client metadata at /api/auth/atproto/client-metadata.json and public keys at /api/auth/atproto/jwks.json. Provider tokens and DPoP keys are encrypted in Postgres and stay on the server. Back up the storage key with the database; changing it requires re-encrypting stored credentials.

For local OAuth, set ATPROTO_PUBLIC_URL=http://127.0.0.1:8183 and launch ./dev.sh 8180. The hosted sign-in page uses http://localhost:8183 and the launcher sets the WebAuthn relying party to localhost. Use the printed URLs; existing passkeys remain bound to their original relying party.

Without an email provider configured, the local launcher also prints sign-in codes in the browser console. This requires development mode, the launcher's FLOW_DEV_OTP_CONSOLE=1 opt-in, and a loopback issuer; the API then binds only to 127.0.0.1. Production responses never include these codes.

AT Protocol requires an IP loopback callback URI. The development landing server redirects loopback GET requests to its fixed localhost origin before handling them, retaining the callback query so OAuth resumes with the same browser cookies and session storage as sign-in. The SDK still exchanges the code using the registered IP callback URI. If that port block is occupied, update ATPROTO_PUBLIC_URL to the selected landing port and restart. Production clients use HTTPS metadata and authenticate with the configured signing key.

Provider sign-in resumes the bound /authorize transaction. Flow installs a first-party session, then returns the existing one-use PKCE code to the app. Account linking returns to /account; no provider or Flow tokens travel in redirect URLs or window messages.

The account connection view reads saved identities and credentials locally. It does not refresh provider tokens or resolve handles on page load; reconnect performs a new provider authorization when access needs to be restored.

Connected accounts

Better Auth owns the shared account model. External identities are keyed by providerId and accountId, and link to the canonical Flow userId. For AT Protocol these values are atproto and the verified DID. Handles are display metadata, never an identity key. A Flow account can connect different providers without adding provider-specific identity tables. Provider IDs identify a trusted provider configuration: separate OIDC issuers must use separate IDs, even if both run the same identity-server software.

Provider credentials and temporary authorization state live in the encrypted, provider-scoped oauth_session and oauth_state stores. The AT SDK uses an adapter over those stores; its DPoP and discovery behavior stays within the AT integration. Provider tokens never become Flow session tokens.

Better Auth supports built-in social providers and its Generic OAuth plugin. Flow currently uses version 1.4.17, whose default OAuth enrollment requires an email and creates its own sessions. A new provider must supply a verified stable subject to Flow's shared account enrollment, then use Flow's audience-bound session issuance. Register usable sign-in providers explicitly; arbitrary account rows do not count as recovery methods. No new identity table is needed.

Automatic email-based account linking is disabled. Disconnect through Flow's account controls so credential cleanup and last-sign-in-method checks run in one transaction; the stock Better Auth unlink endpoint is blocked. Its account listing remains available and excludes credentials.

Migration 0040 preserves existing AT links and encrypted sessions, then removes the earlier AT-only tables. It invalidates in-flight authorization state, so unfinished attempts must restart. Deploy the complete revised Auth stack before enabling AT production configuration. After this migration, the intermediate AT-only builds from PRs #170–#172 are not rollback targets; use the pre-AT main build or a compatible forward fix. Existing pre-AT Flow user/session writes remain supported.

npm: @flow-industries/id

Installation

bun add @flow-industries/id viem

For Wagmi apps:

bun add @flow-industries/id wagmi viem @tanstack/react-query

Documentation

The Auth pages in the separate documentation repository are archived. Use the guides here for the current SDK integration.

Sign-in and account pages

The SDK starts sign-in through your app's first-party /flow/session handler and navigates to Flow ID's /authorize page. Completion returns to the saved app path; read the new session after navigation instead of continuing after await flow.login().

ProfileButton and flow.openAccount() open /account in a normal new tab. The source app stays loaded and refreshes its session on refocus. Sign-in and own-account management no longer use an embedded dialog. The remaining dialog supports signing, public profiles, and widgets. SDK ConnectResponse remains a deprecated type alias for source compatibility; sign-in itself returns through the first-party callback. See the integration guide for server wiring and migration.

Public profile overlays

import { closeProfile, openProfile } from "@flow-industries/id";
import { isValidUsername } from "@flow-industries/id/usernames";

if (isValidUsername(username)) {
  openProfile(username, { onClose: () => resumeInput() });
}

closeProfile();

@flow-industries/id/usernames also exports USERNAME_REGEX and MAX_USERNAME_LENGTH. It has no browser or server dependencies.

OpenProfileOptions.onClose?: () => void fires once after the overlay stops accepting input, before its exit animation finishes. It covers the close button, backdrop, Escape, closeProfile(), and sign-in/sign-out handoffs. The latest successful openProfile call owns the callback, even when switching profiles while open; an omitted callback clears the previous one. Invalid usernames and SSR return false without replacing it. Closing an already closed overlay is a no-op. A callback may open another profile.

React callers pass the same option to useOpenProfile({ onClose: () => resumeInput() }) from @flow-industries/id/react; the callback is captured when its returned opener is called. The overlay belongs to the page and survives component unmounts.

Open from the document that owns the full viewport. Canvas hosts must release pointer lock before opening, then use onClose to restore their input state.

License

MIT

Migration compatibility checks

bun run db:check regenerates into a temporary directory and refuses schema drift or edits to previously committed SQL. CI compares against the PR base or previous main commit. bun run test:migrations exercises the committed chain, the supported previous schema, current projections, older writes after upgrade, and deliberate missing-migration failures. MIGRATION_TEST_DATABASE_URL=postgres://... bun scripts/postgres-acceptance.ts additionally creates a unique disposable database on a test PostgreSQL server, runs the real migration entrypoint, rejects a changed applied hash, and proves a failing final migration rolls back both its schema changes and ledger entry. The test deletes only its own generated database.

The initial compatibility baseline is source 1bda372b69e2f66a3dc0cbb244bcbe7cb858f493 (schema through 0035). The tests freeze representative older SQL reads/writes; they do not boot every historical application version. Advance this baseline deliberately when retiring support, and extend the fixtures when changing a persisted contract. Migration failures block the image build; production's PreSync job also refuses an applied ledger that is not an exact committed prefix.

Application rollback keeps the expanded schema. Pin the latest verified migration image via Mesh's migrate.image while restoring the previous compatible application image. Do not run down migrations or point an older migration image at a newer ledger: that is refused. A destructive contract migration needs an explicit support-boundary change after older writers and browser clients have drained.

Versioned consumer contracts

bun run contracts:generate produces the published @flow-industries/id/contracts/v1/reports.json and openapi.json artifacts from the same schemas used by the XP, action, presence and position handlers. bun run contracts:check rejects stale output and incompatible changes to the existing v1 request schema against CONTRACT_BASE_REF (default origin/main). Keep existing v1 fields compatible; a breaking boundary needs a new version and an overlap plan for deployed consumers.

Trusted service consumers can call createReportsApi(host, serviceToken) from @flow-industries/id. The returned function accepts the operation name and its typed request, validates both the outgoing request and successful response, and throws ReportRequestError for non-success responses. Use the XP reporting credential for action/XP operations and the room credential for presence/position; never ship either service credential to a browser.

bun run test:sdk-package builds, packs and installs the actual SDK artifact in a disposable consumer, checks public imports and declarations, and proves a removed contract export fails. Producer tests execute the typed client against real report handlers and validate minted guest/full session and JWT shapes. CI gates both container and package publication on these checks.

The current OpenAPI artifact describes the service report boundary. The remaining account, room management, study, settings, session and passkey HTTP operations still need complete request/response descriptions and generated client coverage before the full HTTP contract work is complete.

Server deployments may set FLOW_ID_API_URL to a trusted internal HTTP(S) origin for API and JWKS requests, or pass apiUrl to server session/verification helpers. issuerUrl remains the public JWT issuer and browser navigation origin. The transport URL must contain no credentials, path, query, or fragment.