Initial build: stash server + browser extension
Server (Express + better-sqlite3 + FTS5, mirroring keep's stack): /api/capture (upsert-on-url, per PROPOSAL.md's dedup decision), /api/articles (list/search/mark-read/delete), plus a minimal server-rendered reading list and reader view at / and /read/:id (token passed as ?t= there since browser navigation can't set an Authorization header). Bearer-token auth generated via `npm run token` — no login flow, matching keep's one-time identity registration pattern. Extension (Manifest V3, sideloaded, no store distribution): toolbar click or context menu "Send to stash" runs @mozilla/readability (vendored into extension/lib/) against the current page, falling back to raw rendered HTML when extraction comes back too thin. Options page for one-time server URL + token entry. Verified end-to-end with the real extension loaded in a live Chromium instance (not just unit-tested extraction logic): capture against a real page, dedup-on-recapture, mark-read, FTS5 search, 401 on missing auth, and both server-rendered views all confirmed working. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
19
src/server/index.ts
Normal file
19
src/server/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import routes from './routes.js';
|
||||
import ui from './ui.js';
|
||||
|
||||
const app = express();
|
||||
const PORT = Number(process.env.PORT) || 3070;
|
||||
|
||||
app.use(express.json({ limit: '5mb' })); // article HTML can be sizeable
|
||||
app.use(cors()); // the extension calls this from arbitrary page origins
|
||||
|
||||
app.use('/api', routes);
|
||||
app.use('/', ui);
|
||||
|
||||
app.get('/api/health', (_req, res) => res.json({ ok: true }));
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`stash server listening on :${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user