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

@avelonjs/neon

v0.8.1

Published

Neon drivers for Avelon's database, identity, social, tokens, storage, and queue contracts.

Readme

@avelonjs/neon

@avelonjs/neon is the Neon stack for Avelon: a transaction-capable Postgres database, Neon Auth identity and social login, S3 object storage, and Postgres-backed Signets and queues. Reach for this package when you want the same six contracts @avelonjs/supabase covers, without PostgREST or GoTrue.

Installation

bun add @avelonjs/neon
export NEON_DATABASE_URL=postgresql://user:[email protected]/neondb?sslmode=require
export NEON_AUTH_URL=https://ep-xxx.neonauth.net
export NEON_S3_BUCKET=avelon-uploads
export AWS_REGION=us-east-1
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...

Wire drivers only in avelon.config.ts. Application folders never import @neondatabase/serverless or @aws-sdk/client-s3.

Basic Usage

import { createNeonDatabase } from '@avelonjs/neon'
import type { QueryIR } from '@avelonjs/core'

const db = createNeonDatabase({
  url: process.env.NEON_DATABASE_URL,
  instance: 'primary',
})

const latest: QueryIR = {
  table: 'posts',
  mode: 'select',
  select: ['id', 'title'],
  where: [{ kind: 'null', column: 'published_at', negated: true }],
  relations: [],
  order: [{ column: 'published_at', direction: 'desc' }],
  limit: 10,
}

await db.execute(latest)

Capabilities

| Surface | Notable capabilities | | -------- | --------------------------------------------------------------------------------- | | database | transactions: true, upsert: true, returning: true, maxRelationDepth: 8 | | identity | passwords: true, magicLinks: true, mfa: ['totp'], emailVerification: true | | social | providers github, google | | tokens | abilities: true, expiration: true | | storage | signedUrls: true, transforms empty | | queue | delayed: true, retries: true, deadLetter: true |

rowSecurity stays false. Ward predicates still inject into Query IR. Neon is Postgres, so you can compile RLS yourself through raw(); this package does not ship a PostgREST-shaped syncWards() surface.

Database

Query IR, migrations, and schema checks compile through @avelonjs/postgres/sql, the subpath of that package whose import graph carries no bun specifier, so @avelonjs/neon/database runs on Node as well as Bun. raw() returns the @neondatabase/serverless query function.

Reads, writes, rpc(), and migrations go over Neon's HTTP endpoint, which holds no connection between calls. transaction() is the exception: the callback reads rows before deciding what to issue next, and Neon's HTTP transactions are non-interactive, so the first call opens a WebSocket Pool connection and close() ends it. That path needs a global WebSocket, which Node has from 22 on; on older runtimes set neonConfig.webSocketConstructor before the first transaction.

Import from @avelonjs/neon/database rather than the package root when the runtime is Node. The root barrel also exports the queue and token drivers, which are built on Bun's SQL client.

import { createNeonDatabase } from '@avelonjs/neon'

const db = createNeonDatabase({
  migrations: [
    {
      id: '20260828_create_posts',
      up: ['CREATE TABLE posts (id text PRIMARY KEY, title text NOT NULL)'],
      down: ['DROP TABLE posts'],
    },
  ],
})

await db.plan()
await db.apply()
await db.transaction(async (tx) => {
  await tx.execute({
    table: 'posts',
    mode: 'insert',
    select: [],
    where: [],
    relations: [],
    order: [],
    values: { id: 'post-1', title: 'Hello' },
  })
})

Identity

Neon Auth speaks the Better Auth HTTP surface. The config-time factory receives request-scoped cookies.

import { createNeonIdentity } from '@avelonjs/neon'

const auth = createNeonIdentity({
  authUrl: process.env.NEON_AUTH_URL,
})

export async function currentUser(cookies: import('@avelonjs/core').RequestCookies) {
  return auth(cookies).user()
}

Capabilities: passwords: true, magicLinks: true, oauth: false, organizations: false, mfa: ['totp'], emailVerification: true. After password sign-in you challenge the enrolled TOTP factor and verify the authenticator code. challengeMfa() without an argument uses totp. Email confirmation uses Better Auth's send-and-verify token pair.

import { createNeonIdentity } from '@avelonjs/neon'
import type { RequestCookies } from '@avelonjs/core'

export async function completeTotpAndEmail(cookies: RequestCookies) {
  const identity = createNeonIdentity({
    authUrl: process.env.NEON_AUTH_URL,
  })(cookies)

  await identity.signInWithPassword('[email protected]', 'correct-horse-battery')
  const challenge = await identity.challengeMfa('totp')
  await identity.verifyMfa(challenge.id, '123456')
  await identity.sendEmailVerification()
  await identity.verifyEmail('confirmation-token')
}

OAuth linking stays undeclared until a live Neon Auth project exercises that surface in CI.

Social

import { createNeonSocial } from '@avelonjs/neon'

const social = createNeonSocial({
  authUrl: process.env.NEON_AUTH_URL,
})

export async function githubRedirect(callbackUrl: string): Promise<string> {
  return social.redirect('github', callbackUrl)
}

Providers are the literal list github and google. Undeclared providers raise Invalid. A mismatched or missing OAuth state raises Unauthenticated.

Tokens

Neon Auth does not issue named API tokens. Hashed Signets live in Postgres on the Neon database.

import { createNeonTokens } from '@avelonjs/neon'

const tokens = createNeonTokens({
  url: process.env.NEON_DATABASE_URL,
  subject: 'user-1',
})

const issued = await tokens.issue('deployment', { abilities: ['records:read'] })
await tokens.verify(issued.plainText)

Storage

Object bytes persist in S3. Point endpoint at AWS, Cloudflare R2, MinIO, or the in-process LocalS3Server used by conformance. Signed reads are SigV4 query URLs.

import { createNeonStorage } from '@avelonjs/neon'

const disk = createNeonStorage({
  bucket: process.env.NEON_S3_BUCKET,
  instance: 'uploads',
})
await disk.put('avatars/me.bin', new Uint8Array([1, 2, 3]), {
  contentType: 'application/octet-stream',
})
const url = await disk.signedUrl('avatars/me.bin', 60)

Transforms are undeclared in v1 (D28). Signed uploads and listing are deferred.

Queue

Durable jobs use Postgres FOR UPDATE SKIP LOCKED on the Neon database.

import { createNeonQueue } from '@avelonjs/neon'

const queue = createNeonQueue({
  url: process.env.NEON_DATABASE_URL,
})
const id = await queue.enqueue({ name: 'GenerateReport', payload: { reportId: 'report-1' } })
await queue.drain(async (receipt) => {
  if (receipt.id !== id) return
})

Method Reference

| Method / export | Signature | Description | | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | createNeonDatabase | (options?: NeonDatabaseOptions) => NeonDatabase | Constructs the Neon database driver. | | NeonDatabase | class NeonDatabase | Neon database implementation wrapping the Postgres Query IR compiler. | | NeonDatabase.execute | (query: QueryIR) => Promise<QueryResult> | Compiles and executes one query IR operation. | | NeonDatabase.rpc | (routine: string, args: Readonly<Record<string, unknown>>) => Promise<T> | Invokes a Postgres routine; missing routines raise Invalid. | | NeonDatabase.plan | () => Promise<MigrationPlan> | Returns pending migration identifiers and SQL steps. | | NeonDatabase.apply | () => Promise<readonly MigrationStatus[]> | Applies pending migrations. | | NeonDatabase.rollback | (steps?: number) => Promise<readonly MigrationStatus[]> | Rolls back the newest applied migration batches. | | NeonDatabase.status | () => Promise<readonly MigrationStatus[]> | Lists applied and pending migration states. | | NeonDatabase.transaction | (callback) => Promise<T> | Runs a callback inside a Postgres transaction. | | NeonDatabase.resetFixtures | () => Promise<void> | Recreates assay fixtures used by live conformance. | | NeonDatabase.raw | () => NeonSql | Returns the @neondatabase/serverless query function. | | NeonDatabase.close | () => Promise<void> | Closes the underlying SQL client pool. | | neonDatabaseCapabilities | const | Literal database capability declaration. | | NeonDatabaseOptions | interface | Construction options for the database driver. | | NeonSql | type | Vendor client returned by NeonDatabase.raw(). | | PostgresMigration | interface | Driver-owned id, up, and down SQL pair. | | createNeonIdentity | (options?: NeonIdentityOptions) => (cookies: RequestCookies) => NeonIdentity | Returns the pinned config-time identity factory. | | NeonIdentity | class NeonIdentity | Neon Auth identity implementation. | | NeonIdentity.user | () => Promise<NeonActor \| null> | Returns the current actor from the request cookie session. | | NeonIdentity.session | () => Promise<NeonSession \| null> | Returns the current session or null. | | NeonIdentity.register | (email: string, password: string) => Promise<NeonActor> | Registers and establishes a session cookie. | | NeonIdentity.signInWithPassword | (email: string, password: string) => Promise<NeonActor> | Signs in and writes the session cookie. | | NeonIdentity.signOut | () => Promise<void> | Ends the Auth session and clears the cookie. | | NeonIdentity.sendPasswordReset | (email: string) => Promise<void> | Sends a recovery request without revealing account existence. | | NeonIdentity.resetPassword | (token: string, password: string) => Promise<void> | Replaces a password after validating a recovery token. | | NeonIdentity.updatePassword | (password: string) => Promise<void> | Changes the current actor's password. | | NeonIdentity.sendMagicLink | (email: string, redirectTo?: string) => Promise<void> | Sends a passwordless sign-in link. | | NeonIdentity.signInWithMagicLink | (token: string) => Promise<NeonActor> | Redeems a link token for a session. | | NeonIdentity.challengeMfa | (factor?: 'totp') => Promise<MfaChallenge<'totp'>> | Begins a TOTP challenge for the current session. | | NeonIdentity.verifyMfa | (challengeId: string, code: string) => Promise<void> | Verifies a TOTP challenge response. | | NeonIdentity.sendEmailVerification | (email?: string) => Promise<void> | Sends a confirmation message without revealing account existence. | | NeonIdentity.verifyEmail | (token: string) => Promise<void> | Confirms an email address after validating a vendor token. | | NeonIdentity.raw | () => { authUrl: string } | Returns the Auth HTTP root at the vendor boundary. | | neonIdentityCapabilities | const | Literal identity capability declaration. | | NeonIdentityOptions | interface | Construction options for the identity factory. | | NeonActor | interface | Actor payload with id and email. | | NeonSession | interface | Cookie session with access and refresh tokens. | | readSessionCookie | (cookies: RequestCookies, cookieName: string) => NeonSession \| null | Parses the request-scoped session cookie. | | writeSessionCookie | (cookies: RequestCookies, cookieName: string, session: NeonSession) => void | Writes the session cookie for the current request. | | clearSessionCookie | (cookies: RequestCookies, cookieName: string) => void | Deletes the session cookie for the current request. | | DEFAULT_SESSION_COOKIE | string | Default session cookie name. | | LocalAuthServer | class LocalAuthServer | Better Auth-shaped fixture for identity conformance. | | LocalAuthServer.start | () => Promise<string> | Starts the fixture on an ephemeral port. | | LocalAuthServer.reset | () => void | Clears users, sessions, and recovery tokens. | | LocalAuthServer.stop | () => Promise<void> | Stops the fixture listener. | | LocalAuthServer.recoveryToken | (email: string) => string \| undefined | Returns the recovery token issued for an email. | | LocalAuthServer.magicLinkToken | (email: string) => string \| undefined | Returns the magic-link token issued for an email. | | NEON_IDENTITY_ERROR_MAP | readonly { code: string; framework: string; meaning: string }[] | Better Auth error codes and the taxonomy member each becomes. | | LocalAuthServer.verificationToken | (email: string) => string \| undefined | Returns the email confirmation token issued for an email. | | createNeonSocial | (options?: NeonSocialOptions) => NeonSocial | Constructs the Neon Auth social driver. | | NeonSocial | class NeonSocial | Neon Auth social implementation. | | NeonSocial.redirect | (provider: string, callbackUrl: string, state?: string) => Promise<string> | Builds a Better Auth authorize URL and records CSRF state. | | NeonSocial.callback | (provider: string, params: Readonly<Record<string, string>>, callbackUrl: string) => Promise<SocialIdentity> | Verifies state and exchanges the authorization code. | | NeonSocial.raw | () => { authUrl: string } | Returns the Auth HTTP root at the vendor boundary. | | neonSocialCapabilities | const | Literal social provider declaration. | | NeonSocialOptions | interface | Construction options for the social driver. | | NeonSocialProfile | interface | Normalized provider profile. | | LocalSocialServer | class LocalSocialServer | Better Auth-shaped token fixture for social conformance. | | LocalSocialServer.start | () => Promise<string> | Starts the social fixture on an ephemeral port. | | LocalSocialServer.stop | () => Promise<void> | Stops the social fixture listener. | | createNeonTokens | (options?: NeonTokenOptions) => NeonTokens | Constructs the Postgres-backed Signet driver. | | NeonTokens | class NeonTokens | Neon Signet implementation. | | NeonTokens.issue | (name: string, options?: TokenIssueOptions) => Promise<IssuedToken> | Issues a named token and returns plaintext once. | | NeonTokens.verify | (plainText: string) => Promise<TokenRecord> | Authenticates a plaintext token or raises Unauthenticated. | | NeonTokens.list | () => Promise<readonly TokenRecord[]> | Lists metadata for the current subject without plaintext. | | NeonTokens.revoke | (id: string) => Promise<void> | Revokes one token by stable identifier. | | NeonTokens.reset | () => Promise<void> | Recreates the empty signet table. | | NeonTokens.raw | () => SQL | Returns the Bun SQL client at the vendor boundary. | | NeonTokens.close | () => Promise<void> | Closes the SQL client pool. | | neonTokenCapabilities | const | Literal token capability declaration. | | NeonTokenOptions | interface | Construction options for the token driver. | | createNeonStorage | (options?: NeonStorageOptions) => NeonStorage | Constructs the S3 storage driver. | | NeonStorage | class NeonStorage | S3 storage implementation. | | NeonStorage.put | (path: string, contents: Uint8Array \| AsyncIterable<Uint8Array>, options?: { contentType?: string }) => Promise<StorageObject> | Stores bytes and returns metadata. | | NeonStorage.get | (path: string) => Promise<Uint8Array> | Reads object bytes or raises NotFound. | | NeonStorage.delete | (path: string) => Promise<void> | Deletes an object if it exists. | | NeonStorage.exists | (path: string) => Promise<boolean> | Reports whether an object exists. | | NeonStorage.signedUrl | (path: string, expiresInSeconds: number) => Promise<string> | Creates a SigV4 signed read URL. | | NeonStorage.raw | () => S3Client | Returns the AWS S3 client at the vendor boundary. | | neonStorageCapabilities | const | Literal storage capability declaration. | | NeonStorageOptions | interface | Construction options for the storage driver. | | LocalS3Server | class LocalS3Server | Path-style S3 fixture for storage conformance. | | LocalS3Server.start | () => Promise<string> | Starts the S3 fixture on an ephemeral port. | | LocalS3Server.reset | () => void | Clears stored objects. | | LocalS3Server.stop | () => Promise<void> | Stops the S3 fixture listener. | | signedUrlExpiryMs | (url: URL) => number \| undefined | Parses SigV4 query expiry to epoch milliseconds. | | createNeonQueue | (options?: NeonQueueOptions) => NeonQueue | Constructs the skip-locked Postgres queue driver. | | NeonQueue | class NeonQueue | Neon queue implementation. | | NeonQueue.enqueue | (job: QueueJob) => Promise<string> | Enqueues a job for immediate delivery. | | NeonQueue.enqueueAt | (job: QueueJob, availableAt: Date) => Promise<string> | Enqueues a job no earlier than the supplied time. | | NeonQueue.drain | (handler: (receipt: QueueReceipt) => Promise<void>, options?: { queue?: string; limit?: number }) => Promise<number> | Delivers available jobs and counts attempts. | | NeonQueue.retry | (id: string, delaySeconds?: number) => Promise<void> | Releases a failed job, optionally after a delay. | | NeonQueue.failed | (queue?: string) => Promise<readonly FailedQueueJob[]> | Lists retained terminal failures. | | NeonQueue.replay | (id: string) => Promise<void> | Replays a terminal failure with a fresh attempt budget. | | NeonQueue.forget | (id: string) => Promise<void> | Permanently removes a terminal failure. | | NeonQueue.reset | () => Promise<void> | Recreates empty job tables. | | NeonQueue.raw | () => SQL | Returns the Bun SQL client at the vendor boundary. | | NeonQueue.close | () => Promise<void> | Closes the SQL client pool. | | neonQueueCapabilities | const | Literal queue capability declaration. | | NeonQueueOptions | interface | Construction options for the queue driver. |

Testing

Run the shared suites. Identity and social use Better Auth-shaped local servers. Storage uses LocalS3Server so SigV4 signed reads stay fetchable without AWS. Database, tokens, and queue require a reachable Neon or Postgres URL and fail closed when it is missing.

The database driver talks to Neon's HTTP and WebSocket endpoints, which a plain Postgres does not serve. When the configured URL is not a neon.tech host, tests/neon-local.ts starts both endpoints locally in front of that Postgres, so live conformance exercises the real vendor client end to end.

import { identitySuite, storageSuite } from '@avelonjs/conformance/suites'
import {
  createNeonIdentity,
  createNeonStorage,
  LocalAuthServer,
  LocalS3Server,
} from '@avelonjs/neon'

const auth = new LocalAuthServer()
const authUrl = await auth.start()
identitySuite({
  name: 'neon identity',
  create: () => {
    auth.reset()
    return createNeonIdentity({ authUrl })
  },
  recoveryToken: async (email) => {
    const token = auth.recoveryToken(email)
    if (token === undefined) throw new Error(`No recovery token for ${email}`)
    return token
  },
  emailVerificationToken: async (email) => {
    const token = auth.verificationToken(email)
    if (token === undefined) throw new Error(`No verification token for ${email}`)
    return token
  },
})

const s3 = new LocalS3Server()
const endpoint = await s3.start()
storageSuite({
  name: 'neon storage',
  create: () => createNeonStorage({ endpoint, bucket: 'assay' }),
})
bun test
bun run typecheck
reeve docs:check