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

gas-boilerplate

v1.0.2

Published

Boilerplate: Google Apps Script backend + React frontend + MCP

Readme

GAS Boilerplate

Boilerplate untuk membangun admin dashboard + API untuk AI (MCP) dengan biaya server Rp0: frontend React di-build jadi 1 file HTML dan di-serve langsung oleh Google Apps Script, data di Google Sheets.

web/   → React (Vite + Tailwind) — dibuild jadi 1 file HTML
src/   → Backend Google Apps Script (TypeScript, dibundle esbuild)
shared/→ Types + contract API (sumber kebenaran, dipakai frontend & backend)

Quickstart

npm install
npm --prefix web install

# buat project GAS baru
npx clasp create --title "nama-app"

# build + deploy
npm run build
npx clasp push --force
npx clasp deploy

# ambil URL web app dari output deploy, lalu:
#   1. buka editor GAS → Properties → tambah API_KEY (dipakai MCP)
#   2. jalankan fungsi seedSampleData() sekali (bikin akun admin)
#   3. isi web/.env → VITE_DEPLOYMENT_ID=<deployment-id>

Login default: [email protected] / admin123 (bisa diubah lewat halaman Staff).

Develop frontend (hot reload)

# isi web/.env dulu dengan VITE_DEPLOYMENT_ID, lalu:
npm run dev

Vite proxy /exec → deployment GAS. Data tetap dipakai dari spreadsheet asli.

Scaffold project baru dari boilerplate

npm create gas-boilerplate@latest nama-app
# atau: npx gas-boilerplate nama-app
cd nama-app
npm install && npm --prefix web install

Bisa juga langsung dari repo ini: npm run create -- nama-app. Scaffold menyalin boilerplate (tanpa node_modules/dist/.git/packages), mengganti nama package, dan menyiapkan .clasp.json baru.

Menambah fitur baru (contoh pola: src/features/notes/)

  1. Entityshared/types.ts
  2. Sheetsrc/features/<nama>/<Nama>Sheet.ts (extends BaseSheet<T>)
  3. Actionsrc/features/<nama>/<nama>Feature.ts:
    registerAction({
      name: 'notes.list',
      description: 'Lihat semua catatan',
      inputSchema: { type: 'object', properties: {} },
      authLevel: 'user',
      handler: (args, ctx) => notes.getAll(),
    })
  4. Import di entry → tambah import './features/<nama>/...' di src/index.ts
  5. Halamanweb/src/pages/<Nama>.tsx + route di web/src/App.tsx + menu di AppLayout.tsx

Action yang terdaftar otomatis menjadi:

  • REST handler (doPostaction + payload)
  • MCP tool (tools/list + tools/call) — dengan description + inputSchema
  • Frontend dipanggil lewat api.* (withCache untuk baca, mutate untuk tulis)

MCP (hubungkan ke AI)

MCP remote langsung menunjuk ke URL web app (JSON-RPC via doPost). Contoh (opencode):

{
  "mcp": {
    "nama-app": {
      "type": "remote",
      "url": "https://script.google.com/macros/s/<DEPLOY_ID>/exec?apiKey=<API_KEY>",
      "enabled": true
    }
  }
}

Arsitektur

shared/contract.ts  → ActionDef (name, description, inputSchema, handler, authLevel)
src/core/registry.ts→ registerAction() — daftar action tunggal
src/core/http.ts    → dispatcher REST (dari registry)
src/core/mcp.ts     → JSON-RPC tools/list + tools/call (dari registry)
src/core/           → SheetManager, BaseSheet, session, staff, settings, config
src/features/notes/ → contoh feature (demo) — jadikan blueprint fitur kamu
web/src/lib/api.ts  → satu-satunya layer frontend yang tahu backend (kontrak HTTP)

Backend pluggable

Frontend tidak tahu apa-apa soal GAS — ia cuma berbicara lewat kontrak (shared/contract.ts + web/src/lib/api.ts). Backend non-GAS (Express, Supabase, dst) cukup implementasi kontrak yang sama; GAS hanyalah salah satu implementasi.

Perintah

| Perintah | Fungsi | |---|---| | npm run dev | Vite dev server (proxy /exec → GAS) | | npm run build | tsc check + build web + bundle backend → dist/ | | npm run typecheck | Cek tipe backend | | npm run test | Jalankan unit test (vitest) | | npm run lint | Lint (oxlint) | | npm run check | typecheck + lint + test | | npm run push | clasp push | | npm run deploy -- "deskripsi" | build + push + clasp deploy (butuh VITE_DEPLOYMENT_ID di .env) | | npm run create -- <app> | Scaffold project baru | | npm run pack | Cek isi paket npm (npm pack --dry-run) |

Publish ke npm

npm publish                          # publish gas-boilerplate
cd packages/create-gas-boilerplate
npm publish                          # publish create-gas-boilerplate

Pastikan versi kedua paket sinkron dan sudah di-npm login.

Skrip GAS (jalankan dari editor)

| Fungsi | Kegunaan | |---|---| | seedSampleData() | Bikin akun admin + contoh catatan + appName | | resetAllData() | Kosongkan semua sheet | | resetSpreadsheet() | Bikin spreadsheet DB baru |