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

@cyfgoogle/drive-as-socket

v0.1.0

Published

Google Drive appDataFolder messaging for static PWAs — push, receive, and prune immutable file messages over HTTP.

Readme

@cyfgoogle/drive-as-socket

Google Drive appDataFolder messaging for static PWAs — push immutable file messages, receive them over a polling socket, and prune old messages on push. TypeScript source is published as-is (no build step).

Requirements

  • Browser environment (OAuth via Google Identity Services)
  • Google Cloud OAuth 2.0 client ID (Web application)
  • OAuth scope: https://www.googleapis.com/auth/drive.appdata
  • TypeScript ^5 (package ships .ts sources)

Install

npm install @cyfgoogle/drive-as-socket

Setup

  1. Create a Google Cloud project and OAuth Web client credentials.
  2. Add your PWA origin to authorized JavaScript origins.
  3. Create a GoogleOAuth instance and pass it to DriveSocket.connect.

Usage

import { DriveSocket, getOAuthSingleton } from "@cyfgoogle/drive-as-socket";

const oauth = getOAuthSingleton({
  googleApiClientId: "YOUR_CLIENT_ID.apps.googleusercontent.com",
  googleOAuthTokenScopes: ["https://www.googleapis.com/auth/drive.appdata"],
});

// First visit: user must click sign-in (OAuth popup)
await oauth.authenticate();

const socket = await DriveSocket.connect(
  {
    clientType: "single-tenant",
    rootPath: "my-app/messages",
    pollIntervalInMs: 5000,
    maxFiles: 20,
  },
  oauth,
);

// Push a JSON message with a user-provided filename
const fileBlob = new Blob([JSON.stringify({ hello: "world" })], {
  type: "application/json",
});

await socket.push({
  fileBlob,
  mimeType: "application/json",
  fileName: "hello.json",
});

// Receive all folder files each poll cycle (downloaded, newest first)
socket.onReceive(async (messages) => {
  for (const message of messages) {
    const text = await message.fileBlob.text();
    console.log(message.name, text);
  }
});

await socket.disconnect();

On authenticate, GoogleOAuth restores tokens from localStorage when present, or requests new ones via GIS (silent renewal first, then interactive sign-in). Acquired tokens are persisted to localStorage for session continuity across page reloads.

Sign-in uses the GIS token model (no backend client_secret required). After the user approves access once, the library silently requests new access tokens for hours-long sessions.

API

| Method | Description | |--------|-------------| | DriveSocket.connect(config, oauth) | Authenticate via oauth, resolve rootPath, return a connected socket | | disconnect() | Stop polling and mark the socket inactive | | push(payload) | Upload immutable message; returns saved DriveMessage while prune runs in the background | | onReceive(callback) | Poll on pollIntervalInMs; download and emit all folder files each cycle |

onReceive poll cycle

Each cycle:

  1. List all files in the configured folder
  2. Download every file
  3. Invoke the callback once with all DriveMessage values, sorted newest-first
  4. Wait the full pollIntervalInMs, then start the next cycle

If a cycle is still running when pollIntervalInMs would elapse, the timer is held until that cycle finishes. The next cycle always starts after a full pollIntervalInMs wait from completion — elapsed work time is not subtracted from the interval.

Config

| Property | Description | |----------|-------------| | clientType | "single-tenant" (appDataFolder / drive.appdata) or "multi-tenant" (drive / drive.file) | | rootPath | Folder path under the space (created if missing) | | pollIntervalInMs | Poll cycle length in milliseconds | | maxFiles | Maximum files kept in folder (oldest pruned in the background after each push) |

NewMessagePayload

| Property | Description | |----------|-------------| | fileBlob | File contents to upload | | mimeType | Google-supported MIME type | | fileName | Destination file name in the folder |

DriveMessage

Saved message returned from push and onReceive. Extends DriveFileEntry.

| Property | Description | |----------|-------------| | id | Google Drive file ID | | name | File name in the folder | | createdTime | Drive file creation timestamp | | mimeType | File MIME type | | fileBlob | Downloaded file contents | | isError | true when a polled file could not be downloaded |

MIME types

Only Google-supported MIME types in the package allowlist are accepted on push. The filename extension must match the MIME type. HTML, CSS, and JavaScript MIME types are excluded. See exported MIME_TO_EXTENSION and SupportedMimeType.

License

MIT