個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證One inbox for everything you save. Collects bookmarks from your browser, X, Reddit, Instagram, LinkedIn and YouTube Watch Later through a Chrome extension, with AI summaries and search by meaning
翻譯準備中
正在載入完整 README。
檢視完整 README ↗Every post you saved, on every platform, in one inbox — summarised, linked across platforms, and resurfaced so you actually use it.
https://github.com/user-attachments/assets/8dd438a1-adcc-41dd-8c75-b49fd279c393
bookmark-captain-extension.zip
from the latest release
and unzip it into a folder you'll keep. Chrome runs the extension from that folder.chrome://extensions, turn on Developer mode (top right), click Load unpacked
and choose the unzipped folder (the one containing manifest.json).Updates don't install themselves yet: download the new zip, replace the folder's contents, and
click the reload icon (↻) on Bookmark Captain in chrome://extensions.
Using the app? Read the User Guide: setup, connecting platforms, the inbox, and troubleshooting.
utm_*, fbclid, si, …) are stripped, and the same
page saved twice (or from another platform) is detected instead of duplicated.bookmarks.html — exports from Chrome, Firefox, Safari or Edge, with folder paths.apps/
api/ Express 5 API — auth, API tokens, bookmarks, live events (SSE)
web/ Next.js 16 web app (App Router, Tailwind CSS 4, TanStack Query)
extension/ Chrome extension (Manifest V3), bundled with esbuild
packages/
db/ Drizzle ORM schema, Postgres client (Neon-ready), SQL migrations
shared/ Types, zod schemas, URL normaliser; `@bc/shared/constants` is dependency-free
e2e/ Playwright end-to-end tests (API + web + real Chromium with the extension)
Tooling: pnpm workspaces, Turborepo, TypeScript (strict), ESLint (type-aware), Prettier, Vitest + Supertest, Playwright, GitHub Actions CI.
.nvmrc) and pnpm 10 (corepack enable)production, dev (local development) and
test (wiped by the test suites). Docker is optional (pnpm db:up) for working offline.pnpm install
cp .env.example .env # fill in the Neon connection strings (see "Using Neon")
pnpm db:migrate # apply migrations to DATABASE_URL
pnpm dev # API on :4000, web on :3000, extension rebuilt on change
Open http://localhost:3000 and use Development sign-in (any email) — no Google setup needed locally.
pnpm --filter @bc/extension build (or keep pnpm dev running).chrome://extensions, turn on Developer mode, click Load unpacked and choose
apps/extension/dist.The extension is built for the URLs in .env (NEXT_PUBLIC_API_URL, WEB_URL); override with
EXTENSION_API_URL / EXTENSION_WEB_URL for other environments.
| Command | What it does |
|---|---|
pnpm dev | Run every app in watch mode |
pnpm test | Unit + integration tests (uses TEST_DATABASE_URL) |
pnpm test:e2e | End-to-end tests on ports 3100/4100 against TEST_DATABASE_URL |
pnpm lint | ESLint with type-aware rules |
pnpm typecheck | tsc in every package |
pnpm format | Prettier |
pnpm build | Production builds (API bundle, web app, extension) |
pnpm db:generate | Create a SQL migration after editing packages/db/src/schema.ts |
pnpm db:migrate | Apply pending migrations |
pnpm db:studio | Browse the database with Drizzle Studio |
The first pnpm test:e2e needs a browser: pnpm --filter @bc/e2e exec playwright install chromium.
The e2e suite builds its own copies of the web app (apps/web/.next-e2e) and extension
(e2e/.extension), so it never disturbs pnpm dev or your dev data.
| Method & path | Auth | Purpose |
|---|---|---|
GET /bookmarks | session or token | List with view, platform, q, cursor paging |
POST /bookmarks | session or token | Save one link (returns the existing one if saved) |
POST /bookmarks/ingest | session or token | Idempotent bulk upsert (≤ 500 items per request) |
POST /bookmarks/remove | session or token | Mirror deletions made at the source |
PATCH /bookmarks/:id | session or token | Change status / snooze |
DELETE /bookmarks/:id | session or token | Delete |
GET /events | session or token | Server-sent events: bookmarks.changed |
GET/POST /api-tokens | session only | List / create API tokens (e.g. for the extension) |
DELETE /api-tokens/:id | session only | Revoke a token |
DELETE /api-tokens/current | token only | A client revokes its own token (disconnect) |
/auth/*, GET /me | — | Sign-in, sign-out, current user |
Errors always have the shape { "error": { "code", "message", "details?" } }.
dev and test branches
from production (or neonctl branches create --name dev).dev branch, copy the pooled connection string into DATABASE_URL and the
direct one into DATABASE_URL_UNPOOLED. Migrations use the direct connection.test branch's direct connection string into TEST_DATABASE_URL.sslmode=verify-full in every URL.pnpm db:migrateThe production branch is only touched by deployments (pnpm db:migrate with production env vars).
Point your host's health check at /healthz (process liveness, no database access), not
/readyz — frequent readiness probes would keep the Neon compute from scaling to zero.
{API_URL}/auth/google/callback (locally http://localhost:4000/auth/google/callback).GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.HttpOnly, SameSite=Lax
cookie; the database stores only its SHA-256 hash. Sliding 30-day expiry.bct_…) for the extension are also stored hashed, expire after a year, can only be
created from a browser session, and can be revoked from Settings → Connected devices.window.postMessage on the web app's own connect page;
the background worker only accepts it from that exact origin and path.state check.SameSite=Lax plus an Origin allow-list on every cookie-authenticated state change.app.example.com and api.example.com, set COOKIE_DOMAIN=example.com
so the Next.js server can read the session cookie.TRUST_PROXY to the number of proxies in front of the API so client IPs and rate limits are correct.LISTEN/NOTIFY.pnpm --filter @bc/api build && pnpm --filter @bc/api start (bundled to apps/api/dist).