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

@nexus-cross/kyc

v1.3.6

Published

cross-auth KYC integration (identity + Sumsub status). Framework-agnostic core + React adapter.

Readme

@nexus-cross/kyc

KYC integration for cross-auth. A framework-agnostic core plus a thin React adapter that wrap the cross-auth /kyc endpoints:

  • GET /kyc — read-only. Returns the caller's identity (SIWE or social) and the identity-core-api KYC status. No side effects.
  • POST /kyc — links the caller's wallets to the project (idempotent) and, when KYC isn't yet approved, starts/resumes verification (idempotent) and surfaces either a hosted verification_url (preferred) or a Sumsub SDK token. The package enters the flow accordingly — see Launching verification.

The package follows the same hexagonal shape and env-resolution style as @nexus-cross/onramp: pure core (ports/types/use cases) → adapters (HTTP repository + env-based endpoints) → react (Provider + hooks), with a createKyc() facade on top.

Install

pnpm add @nexus-cross/kyc
# React Provider/hooks (the "./react" entry) additionally need:
pnpm add react react-dom

react is an optional peer — only the @nexus-cross/kyc/react sub-entry requires it. The main entry (createKyc, HttpKycRepository, …) is React-free and works in any framework or vanilla JS.

Environment / base URL

Base URL resolution mirrors @nexus-cross/onramp. You normally don't set anything — it picks the cross-auth host from the environment identifier:

| Environment | Base URL | |---|---| | production (default) | https://cross-auth.crosstoken.io/cross-auth | | stage | https://stg-cross-auth.crosstoken.io/cross-auth | | dev | https://dev-cross-auth.crosstoken.io/cross-auth |

Resolution priority:

  1. Explicit baseUrl option passed to createKyc / HttpKycRepository.
  2. VITE_CROSSX_AUTH_BASE_URL (Vite) or NEXT_PUBLIC_CROSSX_AUTH_BASE_URL (Next.js).
  3. Environment identifier VITE_CROSSX_ENVIRONMENT / NEXT_PUBLIC_CROSSX_ENVIRONMENT / CROSSX_ENVIRONMENT (dev | stage | production) → the table above.

Non-https URLs are rejected (except http://localhost for local dev).

Authentication

The /kyc endpoints require auth. Two ways, used together:

  • Bearer token — pass getAccessToken; the repository sends Authorization: Bearer <token>. It's called on every request, so a token refresh is picked up automatically without re-creating the client (don't bake a stale token in). A Bearer prefix in the returned value is de-duplicated.
  • Cookie session — every request is sent with credentials: 'include', so an HttpOnly cross-auth session cookie is attached automatically. If you rely only on cookies, you can omit getAccessToken.

Social login extra headers

For social logins the backend additionally requires X-Project-Id plus a client identifier, otherwise it returns 401:

  • Web — the client identifier is the Origin header, which the browser sends automatically on cross-origin requests (it's a forbidden header, so this package never sets it). Just make sure projectId is set.
  • Native SDK — pass appId (X-App-Id) and appType (X-App-Type) instead.

projectId is sent as X-Project-Id. Use your embedded project id (falling back to the cross project id), the same value connect-kit uses for the embedded wallet. SIWE logins are authenticated by the token/cookie alone and don't need the client identifier.

Quick start — with connect-kit (recommended)

If you use @nexus-cross/connect-kit-react, KYC is auto-wired. Set kycEnabled: true in the kit config; connect-kit mounts the provider and injects the access token from the connected crossx 2.0 SDK session — no token plumbing, no KycProvider:

// config
createConnectKitConfig({ crossProjectId, kycEnabled: true /* … */ });
import { useKyc } from '@nexus-cross/connect-kit-react';

function KycButton() {
  const { verified, status, isLoading, isStarting, refresh, startVerification } =
    useKyc();
  if (verified) return <span>KYC verified ✓</span>;
  return (
    <>
      <button onClick={() => void refresh()} disabled={isLoading}>Check KYC</button>
      <button onClick={() => void startVerification()} disabled={isStarting}>
        Start KYC
      </button>
      <p>status: {status ?? '—'}</p>
    </>
  );
}

X-Project-Id uses embeddedProjectId (falling back to crossProjectId). The token is read per request, so refreshes are picked up automatically.

Quick start — standalone (without connect-kit)

Mount <KycProvider> yourself and supply getAccessToken:

// App.tsx
import { KycProvider } from '@nexus-cross/kyc/react';

export function App() {
  return (
    <KycProvider
      config={{
        projectId: EMBEDDED_PROJECT_ID,
        getAccessToken: () => accessToken, // read latest token here
      }}
    >
      <KycButton />
    </KycProvider>
  );
}
// KycButton.tsx
import { useKyc } from '@nexus-cross/kyc/react';

function KycButton() {
  const { status, verified, isLoading, isStarting, error, refresh, startVerification } =
    useKyc(); // autoFetch: true → GET /kyc on mount

  if (verified) return <span>KYC verified ✓</span>;

  return (
    <div>
      <button onClick={() => void refresh()} disabled={isLoading}>
        {isLoading ? 'Checking…' : 'Check KYC'}
      </button>
      <button onClick={() => void startVerification()} disabled={isStarting}>
        {isStarting ? 'Starting…' : 'Start KYC'}
      </button>
      <p>status: {status ?? '—'}</p>
      {error && <p>error: {error.message}</p>}
    </div>
  );
}

startVerification() runs POST /kyc and then enters the verification flow automatically (see Launching verification). Use the lower-level start() if you want the raw KycIdentity back without launching.

Pass useKyc({ autoFetch: false }) to skip the on-mount GET /kyc and trigger it manually via refresh(). useOptionalKyc() returns the facade or null outside a Provider (for "enable only if mounted" UIs).

Launching verification

POST /kyc (via start() / startVerification()) returns a KycIdentity. How the verification flow is entered depends on what the backend put in it, and the package picks the right path automatically:

| Response field | Behavior | Notes | |---|---|---| | verificationUrl (verification_url) | default — opens the hosted URL in a new tab (window.open) | vendor-neutral; no CDN/CSP. This is the recommended backend contract. | | sdkToken (kyc_token), no URL | fallback — loads the Sumsub WebSDK and launches it in a fullscreen modal | Sumsub CDN coupling is isolated to the browser adapter; token refresh re-calls POST /kyc. | | neither | throws KycError('LAUNCH_FAILED') | — |

  • New tab vs current window: pass target (URL mode only). 'newWindow' (default) opens the URL in a new tab; 'currentWindow' navigates the current tab via location.assign (rely on the backend redirect to return). The WebSDK fallback always renders as a modal in the current window.
    await startVerification({ target: 'currentWindow' });
  • React: useKyc().startVerification(opts?) = start() + launch. Returns { identity, handle }; handle.close() dismisses the WebSDK modal (no-op in URL mode).
  • Framework-agnostic: launchKycVerification(identity, opts) from @nexus-cross/kyc.
  • Completion is authoritative via webhook; poll GET /kyc (refresh()) for the final status regardless of which path was taken.

Quick start — framework-agnostic

import { createKyc, launchKycVerification } from '@nexus-cross/kyc';

const kyc = createKyc({
  projectId: EMBEDDED_PROJECT_ID,
  getAccessToken: () => accessToken,
});

const me = await kyc.getStatus();      // GET /kyc
if (!me.verified) {
  const started = await kyc.start();    // POST /kyc
  // verificationUrl → new tab, else sdkToken → Sumsub WebSDK modal
  await launchKycVerification(started);
}

API

createKyc(options): Kyc

options (CreateKycOptions):

| Option | Type | Notes | |---|---|---| | projectId | string? | Sent as X-Project-Id. Required for social login. | | getAccessToken | () => string \| null \| undefined \| Promise<…> | Bearer token getter, called per request. | | appId | string? | Native SDK flow only → X-App-Id. | | appType | string? | 'android' \| 'ios' \| 'windows'X-App-Type. | | baseUrl | string? | Override the resolved cross-auth base URL. | | repository | KycRepository? | Inject a custom/mock transport. |

Returns { port, getStatus(), start() }.

KycIdentity

Normalized (camelCase) form of cross-auth KYCResp:

| Field | Type | Source | |---|---|---| | status | 'none' \| 'pending' \| 'approved' \| 'rejected_retry' \| 'rejected_final' \| 'wallet_required' | status | | verified | boolean | kyc_verified | | loginType | 'siwe' \| 'social' \| undefined | login_type | | walletAddress | string? | wallet_address | | rejectType | 'RETRY' \| 'FINAL' \| undefined | reject_type (rejected states) | | provider | string? | provider (e.g. "sumsub") | | verificationUrl | string? | verification_url (hosted link → opened directly) | | sdkToken | string? | kyc_token (Sumsub SDK token, WebSDK fallback) | | sdkTokenExpiresAt | string? | kyc_expires_at (ISO) | | email / nickname / sub / uuid | string? | social only |

Errors

Failures throw a KycError with a code: MISSING_PROJECT_ID, UNAUTHORIZED (401/403), STATUS_FAILED, START_FAILED, INVALID_RESPONSE, NETWORK_ERROR, LAUNCH_FAILED (verification could not be opened — popup blocked, SSR, or neither verificationUrl nor sdkToken present). In React, the last error is surfaced via useKyc().error (reads/refresh() capture it; start()/startVerification() also throw so you can try/catch).

Advanced — custom transport

Implement KycRepository to talk to a different gateway or to mock in tests, then inject it:

import { createKyc, type KycRepository } from '@nexus-cross/kyc';

const mock: KycRepository = {
  fetchStatus: async () => ({ status: 'approved', verified: true }),
  initVerification: async () => ({ status: 'approved', verified: true }),
};

const kyc = createKyc({ repository: mock });

License

MIT