个人 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).