Skip to content

Repository files navigation

notejs

A lightweight, serverless note-taking web app written in TypeScript. Create, edit, and share notes with auto-save. Deploys on Cloudflare Workers (native KV) or Vercel Edge (Upstash Redis). No JS frameworks, no build step, zero dependencies — pure vanilla HTML/CSS/JS.

Features

  • Simple Note Editor: Lightweight web interface for creating and editing notes
  • Auto-Save: Automatically saves note content every second
  • Shareable URLs: Notes accessible via direct links with human-friendly WORDnn IDs
  • Multi-Deployment: Cloudflare Workers or Vercel Edge
  • Zero Dependencies: No npm runtime deps — KV via native bindings (Cloudflare) or REST fetch (Vercel)
  • XSS Protection: User content is HTML-escaped
  • Responsive: Works on desktop and mobile
  • Print Support: Print-friendly interface

Quick Start

Prerequisites

  • Node.js 24+

Local Development

The app uses Wrangler (Cloudflare Workers) for local dev. KV is simulated by Miniflare — no account needed:

npm install
npm run dev

Open http://localhost:8787.


Deploy to Cloudflare Workers (recommended)

Storage: Cloudflare KV — persistent, native, zero-config.

Step 1: Create a KV namespace

npx wrangler kv:namespace create "KV"

Step 2: Add the namespace ID to wrangler.toml

Copy the ID from the output and paste it:

[[kv_namespaces]]
binding = "KV"
id = "your-namespace-id"

Step 3: Deploy

npm run deploy

Your app is live at https://your-app.your-account.workers.dev with persistent KV storage.


Deploy to Vercel Edge

Storage: Upstash Redis — persistent with 7-day TTL.

Step 1: Create Upstash Redis (or Vercel KV)

Create a Redis database at upstash.com (free tier). Copy the KV_REST_API_URL and KV_REST_API_TOKEN from the REST API section.

Alternatively, create via Vercel Dashboard: Storage → Create → Redis. This auto-injects the env vars.

Step 2: Set environment variables

npx vercel env add KV_REST_API_URL production --value <your-url>
npx vercel env add KV_REST_API_TOKEN production --value <your-token>

Step 3: Deploy

npx vercel --prod

vercel.json builds src/vercel.ts as an Edge Function and routes all requests to it. The app uses VercelKVStorage which connects to Upstash Redis via its REST API.

Your app is live at https://your-app.vercel.app with persistent KV storage.


CI/CD (GitHub Actions)

The repository includes two workflows:

Test (test.yml)

Runs on every push/PR to feature/typescript:

  • npm citsc --noEmitnpm test

Deploy Cloudflare (deploy-cloudflare.yml)

Manual trigger (workflow_dispatch) — typecheck → deploy to Cloudflare Workers.

Required secret: CF_API_TOKEN — Cloudflare API token with Workers permissions (create in Cloudflare Dashboard → My Profile → API Tokens, template: "Edit Cloudflare Workers").

Deploy Vercel (deploy-vercel.yml)

Manual trigger (workflow_dispatch) — typecheck → deploy to Vercel Edge.

Required secrets:

Secret Description
VERCEL_TOKEN Vercel access token (create in Vercel Dashboard → Settings → Tokens)
VERCEL_ORG_ID Your Vercel team/org ID (from .vercel/project.json)
VERCEL_PROJECT_ID Your Vercel project ID (from .vercel/project.json)

To set up secrets: Go to your GitHub repo → Settings → Secrets and variables → Actions, then add each value. Run workflows via Actions tab → select workflow → Run workflow.

API

GET /noteid/{noteId} (or /?note={noteId})

Retrieve and display a note.

Parameters:

  • noteId (path) or note (query): Note ID (alphanumeric, 3–32 chars, no I/O/0/1)

Notes:

  • The preferred URL format is /noteid/{noteId} for shell-friendly links (e.g., http://example.com/noteid/BLAST47).
  • Backwards compatibility: /?note={noteId} still works.
  • Links use the request host or x-forwarded-* headers for reverse proxy support.
  • Requests with User-Agent containing "curl" return plain text instead of HTML.

POST /

Save or delete a note.

Request body (JSON):

{
  "noteId": "BLAST47",
  "content": "Note content here"
}

Response (JSON):

{
  "success": true,
  "noteId": "BLAST47"
}

Behavior:

  • If noteId is empty, a random WORDnn ID is generated (e.g., "BLAST47")
  • If content is empty or whitespace-only, the note is deleted
  • Otherwise, the note is saved

Examples:

# Create new note
curl -X POST https://your-app.com/ \
  -H "Content-Type: application/json" \
  -d '{"content":"Hello World"}'

# Returns URL for curl requests
curl -X POST https://your-app.com/ \
  -H "Content-Type: application/json" \
  -H "User-Agent: curl/8.0" \
  -d '{"content":"Hello World"}'
# → https://your-app.com/noteid/BLAST47

Project Structure

.
├── src/
│   ├── workers.ts          # Cloudflare Workers entry point
│   ├── vercel.ts           # Vercel Edge entry point
│   ├── handler.ts          # HTTP handlers (GET, POST, OPTIONS)
│   ├── handler.test.ts     # Handler unit tests
│   └── lib/
│       ├── template.ts     # Full HTML/CSS/JS UI template
│       ├── storage.ts      # Storage interface + KV / Vercel KV backends
│       ├── storage.test.ts # Storage unit tests
│       ├── utils.ts        # Note ID generation/validation, HTML escaping, ClientIP
│       └── types.ts        # TypeScript type definitions
├── wrangler.toml           # Cloudflare Workers configuration
├── vercel.json             # Vercel deployment configuration
├── .vercelignore           # Files excluded from Vercel deployment
├── .github/workflows/      # GitHub Actions CI/CD workflows
├── package.json            # Dependencies and scripts
├── tsconfig.json           # TypeScript configuration
└── README.md               # This file

Scripts

Command Description
npm run dev Start local dev server with Wrangler
npm run deploy Deploy to Cloudflare Workers
npm test Run Vitest unit tests
npm run typecheck Run TypeScript type check (tsc --noEmit)

Configuration

Note ID Format

Note IDs use a WORDnn format — a random dictionary word (3–5 uppercase letters, excluding ambiguous characters I/O/0/1) followed by 2 digits. Examples: BLAST47, ACE23, ZEBRA99.

Storage

Both platforms use persistent KV storage with 7-day TTL. Cloudflare Workers uses native Workers KV via env.KV. Vercel Edge uses Upstash Redis via REST API (KV_REST_API_URL / KV_REST_API_TOKEN). Both implement the same Storage interface.

Testing

npm test           # Run Vitest
npm run typecheck  # TypeScript type checking

Security

  • Input validation: Note IDs restricted to [A-HJ-NP-Z2-9]{3,32}
  • XSS protection: User content server-side HTML-escaped before rendering
  • No third-party frontend dependencies

License

MIT License — feel free to use and modify for your needs.

About

Lightweight serverless note-taking app — Cloudflare Workers & Vercel Edge

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages