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

@marcfargas/go-easy

v0.4.0

Published

Google APIs made easy — Gmail, Drive, Calendar for AI agents and humans

Readme

go-easy 🟢

Google APIs made easy — Gmail, Drive & Calendar. For AI agents and humans.

Thin TypeScript wrappers over Google's individual @googleapis/* packages with:

  • Own auth — unified OAuth2 with combined tokens, agent-compatible two-phase flow
  • Agent-friendly types — structured GmailMessage, DriveFile, CalendarEvent
  • Safety guards — destructive operations (send, share, delete) require explicit confirmation
  • JSON gateways — CLI tools that always output structured JSON
  • File-based body — email bodies read from files, not CLI args (no shell escaping issues)

Installation

# As a library
npm install @marcfargas/go-easy

# As CLI tools (no install needed)
npx go-gmail [email protected] search "is:unread"
npx go-drive [email protected] ls
npx go-calendar [email protected] events primary

Requires Node.js ≥ 20.

Auth Setup

go-easy manages its own OAuth2 tokens in ~/.go-easy/.

Prerequisites

  1. Create a project in Google Cloud Console
  2. Enable the Gmail, Drive, and Calendar APIs
  3. Create OAuth2 credentials (Desktop application type)
  4. Save credentials to ~/.go-easy/credentials.json:
{
  "clientId": "YOUR_CLIENT_ID.apps.googleusercontent.com",
  "clientSecret": "YOUR_CLIENT_SECRET"
}

Add an account

npx go-easy auth add [email protected]
# → { "status": "started", "authUrl": "https://accounts.google.com/..." }
# Open the URL, authorize, then poll:
npx go-easy auth add [email protected]
# → { "status": "complete", "email": "[email protected]", "scopes": ["gmail", "drive", "calendar"] }

One combined token covers Gmail + Drive + Calendar. The flow is agent-compatible — two separate CLI calls (start + poll), no streaming stdout needed.

Manage accounts

npx go-easy auth list                         # List configured accounts
npx go-easy auth add [email protected]          # Add or upgrade account
npx go-easy auth remove [email protected] --confirm  # Remove account

Quick Start

import { getAuth } from '@marcfargas/go-easy/auth';
import { search, send } from '@marcfargas/go-easy/gmail';
import { setSafetyContext } from '@marcfargas/go-easy';

const auth = await getAuth('gmail', '[email protected]');

// Search (READ — no safety gate)
const results = await search(auth, { query: 'is:unread from:client' });
console.log(results.items);

// Send (DESTRUCTIVE — requires safety context)
setSafetyContext({
  confirm: async (op) => {
    console.log(`⚠️ ${op.description}`);
    return true; // or prompt the user
  },
});

await send(auth, {
  to: '[email protected]',
  subject: 'Invoice attached',
  markdown: '# Invoice\n\nPlease find attached.',
  attachments: ['./invoice.pdf'],
});

Gateway CLIs

All gateway CLIs output JSON to stdout and work via npx:

# Gmail
npx go-gmail [email protected] search "is:unread" --max=10
npx go-gmail [email protected] get <messageId>
npx go-gmail [email protected] reply <messageId> --body-text-file=reply.txt --confirm
npx go-gmail [email protected] send [email protected] --subject="Hi" --body-text-file=body.txt --confirm

# Drive
npx go-drive [email protected] ls
npx go-drive [email protected] search "quarterly report"
npx go-drive [email protected] upload ./file.pdf --folder=<folderId>

# Calendar
npx go-calendar [email protected] events primary --from=2026-02-01T00:00:00Z
npx go-calendar [email protected] create primary --summary="Meeting" --start=... --end=...
npx go-calendar [email protected] freebusy primary --from=... --to=...

Body content is always read from files (--body-text-file, --body-html-file, --body-md-file), never passed inline.

Destructive operations require --confirm. Without it, they show what would happen and exit with code 2.

Services

| Service | Module | Gateway | Status | |---------|--------|---------|--------| | Gmail | @marcfargas/go-easy/gmail | npx go-gmail | ✅ Ready | | Drive | @marcfargas/go-easy/drive | npx go-drive | ✅ Ready | | Calendar | @marcfargas/go-easy/calendar | npx go-calendar | ✅ Ready |

Gmail

| Function | Safety | Description | |---|---|---| | search | READ | Search messages by Gmail query | | getMessage | READ | Get a single message with parsed fields | | getThread | READ | Get a full conversation thread | | listLabels | READ | List all labels | | getAttachmentContent | READ | Download an attachment as Buffer | | getProfile | READ | Get the authenticated email address | | createDraft | WRITE | Create a draft (no send) | | listDrafts | READ | List existing drafts | | batchModifyLabels | WRITE | Add/remove labels on multiple messages | | markdownToHtml | — | Convert Markdown to email-safe HTML | | send | ⚠️ DESTRUCTIVE | Send a new email (supports markdown option) | | reply | ⚠️ DESTRUCTIVE | Reply / reply-all to a message | | forward | WRITE / ⚠️ DESTRUCTIVE | Forward as draft (default) or send (sendNow). Attachment filtering. | | sendDraft | ⚠️ DESTRUCTIVE | Send an existing draft |

Drive

| Function | Safety | Description | |---|---|---| | listFiles | READ | List folder contents or query by metadata | | searchFiles | READ | Full-text search inside file contents | | getFile | READ | Get file metadata by ID | | downloadFile | READ | Download binary files as Buffer | | exportFile | READ | Export Workspace files (Docs → pdf/docx, Sheets → xlsx/csv, etc.) | | listPermissions | READ | List sharing permissions on a file | | uploadFile | WRITE | Upload a local file | | createFolder | WRITE | Create a folder | | moveFile | WRITE | Move a file to a different folder | | renameFile | WRITE | Rename a file | | copyFile | WRITE | Copy a file | | trashFile | ⚠️ DESTRUCTIVE | Trash a file | | shareFile | ⚠️ DESTRUCTIVE* | Share a file (*public sharing only; user/group is WRITE) | | unshareFile | ⚠️ DESTRUCTIVE | Remove a sharing permission |

Calendar

| Function | Safety | Description | |---|---|---| | listCalendars | READ | List all calendars for the account | | listEvents | READ | List events with time range, search, pagination | | getEvent | READ | Get a single event by ID | | queryFreeBusy | READ | Check availability across calendars | | createEvent | WRITE | Create an event (with attendees, all-day, location, OOO, focus time) | | updateEvent | WRITE | Update an existing event (full replace) | | deleteEvent | ⚠️ DESTRUCTIVE | Delete an event (warns about attendee cancellation) |

Safety Model

Operations are classified into three levels:

| Level | Gate | Examples | |-------|------|----------| | READ | None | search, getMessage, listLabels | | WRITE | Logged | createDraft, batchModifyLabels, upload | | DESTRUCTIVE | Blocked unless confirmed | send, reply, forward, share, delete |

Set up a SafetyContext at startup to handle confirmation prompts. Without one, all destructive operations are blocked by default.

Module Structure

go-easy uses subpath exports — import only what you need:

import { getAuth } from '@marcfargas/go-easy/auth';
import { search, send } from '@marcfargas/go-easy/gmail';
import { listFiles, uploadFile } from '@marcfargas/go-easy/drive';
import { listEvents, createEvent } from '@marcfargas/go-easy/calendar';
import { setSafetyContext } from '@marcfargas/go-easy';

| Import path | What's in it | |---|---| | @marcfargas/go-easy | Safety context, errors, plus gmail/drive/calendar as namespaces | | @marcfargas/go-easy/auth | getAuth, listAccounts, listAllAccounts, clearAuthCache | | @marcfargas/go-easy/auth-store | readAccountStore, writeAccountStore, findAccount, etc. | | @marcfargas/go-easy/scopes | SCOPES, ALL_SCOPES, scopeToService | | @marcfargas/go-easy/gmail | All Gmail operations | | @marcfargas/go-easy/drive | All Drive operations | | @marcfargas/go-easy/calendar | All Calendar operations |

Development

npm install        # install deps
npm run build      # compile TypeScript
npm test           # run tests (vitest)
npm run lint       # type-check without emitting
npm run dev        # watch mode

License

MIT