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

@nextyugai/drive-file-picker

v0.2.0

Published

Thin iframe wrapper for the NextYug Drive file picker. The only thing a client app installs.

Readme

@nextyugai/drive-file-picker

One npm package. Your app gets a file picker; NextYug Drive keeps the files.

Client apps implement no storage, no upload logic, and hold no storage credentials. The package is a thin iframe wrapper around the drive's own media manager, so there is one UI codebase and one place to fix bugs.

npm install @nextyugai/drive-file-picker

Public on npmjs. No registry configuration, no token.

Release candidates go to the nextyug feed on Azure Artifacts first. Point the @nextyugai scope at it in your .npmrc — safe to commit, because the token comes from the environment:

@nextyugai:registry=https://pkgs.dev.azure.com/nextyug/_packaging/nextyug/npm/registry/
//pkgs.dev.azure.com/nextyug/_packaging/nextyug/npm/registry/:username=nextyug
//pkgs.dev.azure.com/nextyug/_packaging/nextyug/npm/registry/:_password=${AZURE_ARTIFACTS_NPM_TOKEN}
//pkgs.dev.azure.com/nextyug/_packaging/nextyug/npm/registry/:[email protected]

AZURE_ARTIFACTS_NPM_TOKEN is an Azure DevOps PAT with Packaging (Read) scope, base64-encoded.

Peer dependency: React 18+. ~3.3 KB gzipped. ESM + CJS, types included.


Setup, end to end

1. One env var on your backend

DRIVE_URL=http://localhost:4000       # dev — no cloud dependency
DRIVE_URL=https://drive.nextyug.ai    # prod
NEXTYUG_DRIVE_APP_KEY=nyd_...         # server-side only, never in a bundle

Get the app key from a drive admin: Admin → Apps → New app. You give them the origins your app runs on; they hand back an appId and a key shown exactly once.

2. One backend route

It exists so the app key never reaches a browser. Roughly fifteen lines:

// app/api/drive/session/route.ts  (Next.js App Router)
export async function POST() {
  const user = await getCurrentUser()          // your existing auth

  const res = await fetch(`${process.env.DRIVE_URL}/api/v1/connect`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.NEXTYUG_DRIVE_APP_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      externalTenantId: user.schoolId,          // stable org id in YOUR app
      tenantName: user.schoolName,
      externalUserId: user.id,
      userEmail: user.email,
      userName: user.name,
      scopes: ['read', 'write'],
      pathPrefix: `${user.schoolId}/`,          // optional hard scope
    }),
  })

  // Return ONLY the session token to the browser.
  return Response.json(await res.json())
}

/api/v1/connect is idempotent. Call it on every login — the first call provisions the org and its bucket, later calls return the same one. There is no separate "already connected" path to maintain.

3. Wrap your app once

import { DriveProvider } from '@nextyugai/drive-file-picker'

<DriveProvider getSession={() => fetch('/api/drive/session', { method: 'POST' }).then(r => r.json())}>
  {children}
</DriveProvider>

The frontend needs zero drive config. The iframe origin comes from the connect response, so the iframe can never point somewhere the token didn't come from.

4. Pick files anywhere

import { FilePicker } from '@nextyugai/drive-file-picker'

<FilePicker
  open={open}
  onClose={() => setOpen(false)}
  appId="app_a91f"
  accept={['image/*', 'application/pdf']}
  multiple
  maxSize={25 * 1024 * 1024}
  folder="students/photos"
  onSelect={(files) => saveAvatarId(files[0].id)}
/>

5. Render stored files

import { DriveImage, DriveFile } from '@nextyugai/drive-file-picker'

<DriveImage fileId={student.avatarId} alt="" />

<DriveFile fileId={doc.id}>
  {({ url, missing }) =>
    missing ? <span>Removed</span> : <a href={url ?? '#'}>Download</a>
  }
</DriveFile>

Store the id, never a URL

onSelect gives you:

type DriveFile = {
  id: string          // ← store THIS
  name: string
  mimeType: string
  size: number
  width?: number
  height?: number
  provider: 'nextyug' | 's3' | 'azure' | 'gdrive'
  createdAt: string
}

There is deliberately no url field. Signed URLs expire. If one were exposed here, someone would write INSERT INTO students (avatar) VALUES (file.url), it would pass review, work in testing, and break a week later — by which point it is a data migration.

<DriveImage> and <DriveFile> fetch a fresh signed URL and refresh it before it expires. Server-side, call GET /api/v1/files/:id/url.

A quick way to check you got this right:

grep -rE "signedUrl|drive.*\.url" src/   # should find no persisted URLs

API

| Export | Purpose | |---|---| | <DriveProvider> | Holds the session token, refreshes before expiry, resolves the embed origin | | <FilePicker> | Modal picker | | <DriveImage> | Renders a stored fileId, auto-refreshing its signed URL | | <DriveFile> | Render-prop version for non-images (downloads, video, PDF) | | useDrive() | Session, embed origin, and getToken() for your own calls |

<FilePicker> props

| Prop | Type | Notes | |---|---|---| | open / onClose | boolean / () => void | You own the open state | | onSelect | (files: DriveFile[]) => void | Fires once, then the modal closes | | appId | string | Your registered app id — goes in the iframe URL | | accept | string[] | e.g. ['image/*']. UX only — the drive re-validates on upload | | multiple | boolean | Default false | | maxSize | number | Bytes. UX only — enforced server-side too | | folder | string | Opens the picker at this path | | zIndex | number | Default 1000. Raise only if your app stacks higher | | onError | (msg: string) => void | Session and upload failures |


Security model

  • App key is server-side only. If a build can put it in a browser bundle, the design is wrong.
  • Session tokens are short-lived (15 min), bound to one tenant, one user, explicit scopes and an optional path prefix. The drive re-validates scope on every call — nothing the iframe claims is trusted. A read session cannot upload; a write session cannot delete.
  • The token is delivered by postMessage, never as a URL query param. Query params leak into referrers, history and server logs.
  • Both sides check event.origin and reject silently otherwise.
  • frame-ancestors is an exact-match allowlist per app. No wildcards. An unregistered origin gets nothing — the embed refuses to render.
  • The iframe runs with sandbox="allow-scripts allow-same-origin allow-forms allow-popups" and nothing broader.

Deleted files

Deletes make GET /files/:id/url return 404, and <DriveImage> renders a placeholder rather than a broken image. Broken references are expected and fail gracefully — there is deliberately no cross-app reference counting, which would be a distributed GC problem.

Local development

Point DRIVE_URL at a local drive instance. No cloud dependency, and no frontend config change — the embed origin follows the connect response.

Not in v0

<DriveEmbed> (full manager iframe), useFilePicker() headless trigger, connector/trash views, and Vue/Svelte bindings. Ask when a real project needs one; DriveEmbed in particular will be designed better after one real integration exists.