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

create-nextcap

v0.1.0

Published

Create Next.js + Capacitor apps with Cloudflare Workers & OTA updates

Readme

create-nextcap

CLI untuk scaffolding project Next.js + Capacitor dengan deploy ke Cloudflare Workers dan sistem OTA update built-in.

Satu codebase → Web + iOS + Android, deploy tanpa Vercel, update tanpa submit ke store.

Stack

| Teknologi | Fungsi | |-----------|--------| | Next.js 16 | Framework React (App Router, SSR, API Routes) | | Capacitor | Native wrapper iOS & Android | | Cloudflare Workers | Hosting (via OpenNext) | | Cloudflare R2 | Storage bundle OTA | | Tailwind CSS 4 | Styling | | @capgo/capacitor-updater | OTA update engine | | npm workspaces | Monorepo |

Prerequisites

Xcode dan Android Studio hanya dibutuhkan saat development native. Web development (npm run dev) tidak memerlukan keduanya.

Quick Start

npx create-nextcap my-app
cd my-app
npm run dev

CLI akan menanyakan:

| Prompt | Contoh | Keterangan | |--------|--------|------------| | Project name | my-app | Nama folder & package | | Display name | My App | Nama yang tampil di device | | Bundle ID | com.example.myapp | ID unik app di store | | Deploy domain | app.example.com | Domain Cloudflare Workers |

Struktur Project

my-app/
├── package.json                             # Monorepo root (npm workspaces)
├── OTA.md                                   # Dokumentasi lengkap OTA
│
├── apps/
│   └── mobile/                              # Next.js app
│       ├── app/                             # Pages (App Router)
│       │   ├── layout.tsx                   # Root layout + OTA provider
│       │   ├── page.tsx                     # Halaman utama
│       │   ├── globals.css
│       │   └── api/ota/                     # API routes (jalan di Cloudflare)
│       │       ├── update/route.ts          # POST — cek update (dipanggil plugin)
│       │       ├── upload/route.ts          # POST — upload bundle baru
│       │       ├── download/[version]/route.ts  # GET — download bundle zip
│       │       ├── manifest/route.ts        # GET — lihat semua versi
│       │       └── rollback/route.ts        # POST — rollback ke versi lama
│       │
│       ├── lib/
│       │   ├── r2.ts                        # Helper akses R2
│       │   ├── auth.ts                      # Validasi API key
│       │   ├── OTAProvider.tsx              # Init OTA di native platform
│       │   └── ota-updater.ts              # Event listeners capacitor-updater
│       │
│       ├── scripts/
│       │   └── ota-deploy.sh               # Build → zip → upload ke API
│       │
│       ├── capacitor.config.dev.ts          # Dev: live reload, OTA off
│       ├── capacitor.config.prod.ts         # Prod: OTA on, auto update
│       ├── next.config.ts                   # Toggle static/server mode
│       ├── wrangler.json                    # Cloudflare Workers + R2 binding
│       ├── .env.example                     # Template env vars
│       ├── .dev.vars.example                # Template Cloudflare local vars
│       │
│       ├── android/                         # Native Android (auto-generated)
│       └── ios/                             # Native iOS (auto-generated)
│
└── packages/
    └── shared/                              # Shared TypeScript types
        └── src/
            ├── index.ts
            └── ota.ts                       # OTAManifest, OTAUpdateRequest, dll

Dua Mode Build

Satu codebase, dua output:

| Mode | Command | Output | Tujuan | |------|---------|--------|--------| | Server | npm run deploy | SSR + API routes | Deploy ke Cloudflare Workers | | Static | npm run build:cap | HTML/CSS/JS static | Bundle Capacitor (mobile) |

Saat build:cap, folder app/api/ sementara di-rename agar Next.js tidak compile API routes dalam mode static export. Setelah build selesai, folder dikembalikan otomatis.

Commands

# ─── Development ─────────────────────────────────────────
npm run dev                  # Dev server (pages + API)
npm run dev:ios              # Dev + buka Xcode
npm run dev:android          # Dev + buka Android Studio

# ─── Build Native ───────────────────────────────────────
npm run build:ios            # Build + open Xcode
npm run build:android        # Build + open Android Studio
npm run build:cap            # Build static saja

# ─── Deploy ─────────────────────────────────────────────
npm run deploy               # Deploy ke Cloudflare Workers

# ─── OTA ────────────────────────────────────────────────
npm run ota:deploy            # Build + zip + upload OTA bundle

Setup Cloudflare

1. Login

npx wrangler login

2. Buat R2 Bucket

npx wrangler r2 bucket create <project-name>-ota

3. Setup Environment Variables

cd apps/mobile

# Untuk local development
cp .dev.vars.example .dev.vars

# Untuk OTA deploy script
cp .env.example .env.local

Edit kedua file:

.dev.vars — Cloudflare bindings lokal:

OTA_API_KEY=your-secret-key-here

.env.local — OTA deploy script:

OTA_API_URL=https://app.example.com
OTA_API_KEY=your-secret-key-here

4. Deploy

npm run deploy

Output: https://<project>.<account>.workers.dev

5. Set Secret di Cloudflare Dashboard

  1. Workers & Pages → worker kamu → SettingsVariables and Secrets
  2. Tambah OTA_API_KEY → isi value → klik Encrypt

6. Custom Domain (opsional)

  1. Workers & Pages → worker kamu → SettingsDomains & Routes
  2. Add Custom Domain → masukkan domain kamu
  3. Pastikan domain nameserver-nya sudah di Cloudflare

7. Verifikasi

curl https://app.example.com/api/ota/manifest
# → {"latest":{"ios":"0.0.0","android":"0.0.0"},"versions":[]}

OTA Update

Push update ke user tanpa submit ulang ke store. Berlaku untuk perubahan JS/HTML/CSS.

Deploy OTA

# 1. Bump version di apps/mobile/package.json
# 2. Jalankan:
OTA_API_URL=https://app.example.com \
OTA_API_KEY=your-secret \
npm run ota:deploy

Script melakukan: build static → zip → upload ke R2 → update manifest.

Opsi

# Platform tertentu
npm run ota:deploy -- android
npm run ota:deploy -- ios

# Dengan catatan rilis
npm run ota:deploy -- all "Fix bug checkout"

# Force update
npm run ota:deploy -- all "Critical fix" true

# Minimum native version
npm run ota:deploy -- all "New feature" false 10

Flow di Device

User buka app
     │
     ▼
OTAProvider → notifyAppReady()
     │          (wajib, kalau tidak dipanggil → auto rollback)
     ▼
Plugin cek /api/ota/update
     │
     ├── Tidak ada update → app jalan normal
     │
     └── Ada update → download di background
                       │
                       ▼
                  User buka app lagi → pakai bundle baru
                       │
                       ├── notifyAppReady() → berhasil!
                       └── Crash → auto rollback ke versi sebelumnya

Rollback

Otomatis: Kalau bundle baru crash dan notifyAppReady() tidak terpanggil, plugin auto rollback.

Manual:

curl -X POST https://app.example.com/api/ota/rollback \
  -H "Authorization: Bearer your-secret" \
  -H "Content-Type: application/json" \
  -d '{"version": "0.1.0", "platform": "all"}'

Cek versi aktif

curl https://app.example.com/api/ota/manifest

API Endpoints

| Method | Endpoint | Auth | Deskripsi | |--------|----------|------|-----------| | POST | /api/ota/update | - | Cek update (dipanggil oleh plugin) | | GET | /api/ota/download/:version | - | Download bundle zip | | GET | /api/ota/manifest | - | Lihat semua versi | | POST | /api/ota/upload | Bearer | Upload bundle baru | | POST | /api/ota/rollback | Bearer | Rollback ke versi tertentu |


OTA vs Store?

| Perubahan | Deploy via | |-----------|------------| | Fix bug UI, tambah halaman, ubah logic JS, update styling | OTA | | Install plugin native baru, update versi plugin native, ubah appId/permissions | Store |

Prinsip: perubahan JS/HTML/CSS → OTA. Perubahan native code → store.


Environment Variables

| Variable | File | Deskripsi | |----------|------|-----------| | OTA_API_KEY | .dev.vars, .env.local, Cloudflare Dashboard | Secret key autentikasi | | OTA_API_URL | .env.local | URL server | | CAPACITOR_BUILD | Otomatis | 1 = static export |


Cloudflare Worker Size Limit

| Plan | Limit | Harga | |------|-------|-------| | Free | 3 MB | Gratis | | Paid | 10 MB | $5/bulan |

Yang dihitung hanya server-side code (API routes + SSR). Static assets (CSS, JS client, gambar, font) diserve lewat CDN, tidak masuk hitungan. Bundle OTA disimpan di R2.


Icon & Splash Screen

Project ini tidak menyertakan icon dan splash screen. Generate sendiri:

cd apps/mobile

# Taruh file sumber di assets/:
#   icon-only.png        (1024x1024, logo saja)
#   icon-foreground.png  (1024x1024, logo dengan padding)
#   icon-background.png  (1024x1024, warna background)
#   splash.png           (2732x2732, splash screen)
#   splash-dark.png      (2732x2732, splash screen dark mode)

npx @capacitor/assets generate

Ini auto-generate semua ukuran icon dan splash screen untuk iOS dan Android.


License

MIT