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

@railrepay/app-core

v1.1.0

Published

Platform-agnostic client core for RailRepay apps — zod schemas (check-delay/login/ticket-upload), bff-client, check-delay-payload builder, and the zustand auth-store. Consumed by web-app-pwa and the Expo app (ADR-033).

Downloads

155

Readme

@railrepay/app-core

Platform-agnostic client core for RailRepay apps, extracted from web-app-pwa per ADR-033 (BL-367 / APPCORE-001a).

Consumed by both web-app-pwa (immediately) and the Expo app (R1 sibling).

Contents (src/)

| Module | Purpose | |--------|---------| | schemas/check-delay.ts | Zod schemas for POST /api/journeys/check-delaybyte-identical ADR-027 client contract | | schemas/login.ts | UK phone + OTP zod schemas, normalizeToE164 | | schemas/ticket-upload.ts | Zod schema for the BFF ticket-upload response | | check-delay-payload.ts | Pure ExtractedFields → CheckDelayRequest builder | | auth-store.ts | Zustand in-memory auth store (react is a peer dependency) | | bff-client.ts | Typed fetch wrapper for the web-app-bff API |

Platform-agnostic guarantee (AC-3)

src/ must contain no next / react-dom / react-native / expo-* imports and no DOM-global usage (window., document., localStorage., …). Enforced by the platform-agnostic-gate job in CI.

Testing

Vitest (ADR-004 / ADR-035 pure-TS carve-out). Coverage gate: ≥80/80/80/75.

npm run test --workspace=@railrepay/app-core
npm run test:coverage --workspace=@railrepay/app-core

React Native usage

Resolved at BL-385 (injectable baseUrl) + BL-386 (crypto.randomUUID guard), Technical Debt workflow TD-2 — these were previously tracked as "Known RN caveats" pending at APPCORE-001c; both are now handled by bff-client.ts itself rather than requiring RN-side workarounds.

1. Polyfill crypto.randomUUID with expo-crypto

bff-client.ts calls crypto.randomUUID() to generate the X-Correlation-ID header (ADR-002) on every request. This is a standard Web Crypto API global in browsers, Node 19+, and Next.js, but React Native does not provide it natively. Without a polyfill, every @railrepay/app-core client call throws a descriptive error naming expo-crypto and this section — install expo-crypto and polyfill globalThis.crypto.randomUUID once, near your app's entry point, before any @railrepay/app-core call:

// entry-shim.ts — import this before anything that uses @railrepay/app-core
import * as ExpoCrypto from 'expo-crypto';

if (typeof globalThis.crypto === 'undefined') {
  // @ts-expect-error — RN has no global `crypto` object at all
  globalThis.crypto = {};
}
if (typeof globalThis.crypto.randomUUID !== 'function') {
  globalThis.crypto.randomUUID = ExpoCrypto.randomUUID as typeof crypto.randomUUID;
}

2. Configure an absolute baseUrl

On the web PWA, Next.js rewrites() proxies /api/* to the BFF same-origin, so the default relative baseUrl ('', BL-273 invariant) works without configuration. React Native has no such same-origin proxy, so RN apps must configure an absolute base URL once at startup:

import { configureBffClient } from '@railrepay/app-core';

configureBffClient({ baseUrl: 'https://bff.railrepay.example.com' });

Every client call (startOtp, verifyOtp, uploadTicket, checkDelay, getMe) is then joined against this base via the joinUrl primitive (joinUrl(base, path) — exactly one trailing slash is stripped from base; path must be /-prefixed). Re-configuring is last-wins; call configureBffClient({ baseUrl: '' }) to reset to the relative default. getMe's own per-call baseUrl parameter (used by the PWA's Next.js middleware) still takes precedence over configureBffClient when both are given.