28 Commits
Author SHA1 Message Date
Claude 58e5b5dd66 feat(editor): make code snippets readable and syntax highlighted
Closes #90.

Code blocks and inline code inherited the typography plugin's defaults,
which shrank them to ~86% of an already-monospace body and painted them
--bg-surface — the same colour as the default note card — so a snippet
was only recognisable by being smaller. Long lines also grew a horizontal
scrollbar inside card previews.

- New --code-bg surface (one step below the page in light mode, page-level
  ink in dark) with a subtle border, and code keeps the surrounding text
  size. Decorative backtick pseudo-elements dropped now that the chip
  carries the signal.
- Card previews clip wide code instead of scrolling; editor and share page
  keep horizontal scroll.
- Syntax highlighting via one shared lowlight instance feeding both the
  TipTap editor (extension-code-block-lowlight) and the markdown-it
  renderer, so a fence looks identical in the editor, on cards and on the
  share page. Only highlight.js "common" grammars are bundled.
- No auto-detection: highlight.js misreads note-sized snippets too often
  (JavaScript as CSS, SQL as VB.NET). Unlabelled fences stay plain; the
  language comes from the fence info string or a toolbar picker shown
  while the cursor is in a code block.
- Six --hl-* token colours per theme; a unit test parses app.css and
  asserts AA contrast against --code-bg and mutual distinguishability.
- Sanitizer now allows only language-* / hljs-* classes on code and span.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014u5WimmZvshm9RJSd1c6wx
2026-09-17 21:42:35 +02:00
Frederic Cabassut e8c30c518c revert: pin better-sqlite3 back to v11.10.0, breaks CI native builds
v13.0.3 has no prebuilt binary for the exact platform/Node combo used
by both this project's Docker build stage (node:22-slim) and the
GitHub Actions E2E runner, so it falls back to compiling from source
via node-gyp. Neither environment has python3/make available for that
fallback, so both the Docker Build and E2E Tests CI jobs failed with
"Could not find any Python installation" / "not found: make".

This wasn't fixing a known vulnerability (audit was already clean), so
revert rather than start patching the Docker image and CI workflow's
system packages for a version-currency bump.
2026-09-02 09:34:03 +02:00
Frederic Cabassut 84145de3b1 chore(deps): remove obsolete @types/uuid stub
uuid v14 ships its own type definitions; @types/uuid now publishes as
an empty stub explicitly saying it's no longer needed.
2026-09-02 09:34:03 +02:00
Frederic Cabassut ea66e23178 chore(deps): update better-sqlite3 to v13 (N-API rewrite)
v13 rewrote the native binding on top of N-API for better cross-version
binary compatibility; no application-facing API changes for the query
methods this app uses. Compiled and verified against the full DB test
suite (notes, versions, shares, collaborators, tags, search, api-keys).
Bumped @types/better-sqlite3 to match.
2026-09-02 09:34:03 +02:00
Frederic Cabassut feda983393 chore(deps): update argon2 to v0.45.1
No API changes (build system tweaks, dropped Node 18/20 support - this
project already targets Node 22+). Verified against the password
hash/verify test suite.
2026-09-02 09:34:03 +02:00
Frederic Cabassut bf5bfdd98e chore(deps): update uuid to v14
No code changes needed - the project is already full ESM ("type":
"module") and only uses the ESM v4 import, so v12's CommonJS removal
doesn't apply here.
2026-09-02 09:34:03 +02:00
Frederic Cabassut 12ff6d9c4d chore(deps): update markdown-it to v15 for quadratic-complexity fixes
v15.0.1 fixes quadratic-complexity bugs in the linkify inline rule and
fuzzy-link replacement - relevant here since this app renders notes
with linkify: true. Also drops @types/markdown-it, which v15 makes
redundant by bundling its own TypeScript declarations (conflicting
otherwise), and adapts two call sites to the now-more-precise
attrGet() return type (string | number | null vs the community types'
string | null).
2026-09-02 09:34:03 +02:00
Frederic Cabassut 44963bf684 chore(deps): fix nanoid vulnerability and update dependencies within semver range
- Add a scoped pnpm override forcing postcss's transitive nanoid to
  >=3.3.18 <4, patching GHSA-2v37-7h3g-55p8 (indefinite loop in custom
  generators with size=0). Scoped to postcss's own dependency rather
  than the top-level nanoid so the app's own nanoid@5 usage is
  untouched.
- Update all other dependencies within their existing package.json
  semver ranges (tiptap, markdown-it, nodemailer, svelte-dnd-action,
  zod, sveltejs/kit, svelte, svelte-check, tsx and their @types).

pnpm audit: 1 high -> 0 vulnerabilities.
2026-09-02 09:34:03 +02:00
Frederic Cabassut 27c3e7dccd fix(editor): render the table-with-list HTML fallback safely instead of escaping it
The table markdown fallback (previous commit) embeds raw HTML in saved
markdown when a cell holds a bullet list, since GFM can't express block
content in a table cell. But the read-only renderer (note-card preview,
public share page) ran with html:false, so that HTML rendered as
escaped literal text instead of a table - moving the bug rather than
fixing it.

Enable html mode and sanitize the rendered output with sanitize-html.
Sanitizing matters beyond this one fallback: note content isn't only
ever written through the editor - the MCP server and notes API accept
a raw markdown string directly, bypassing the editor's schema, so any
HTML this renders has to be treated as untrusted regardless of source.

Also make the table's HTML fallback respect the editor's own `html`
option (falls back to a `[table]` placeholder when disabled), matching
every other node type's markdown storage in tiptap-markdown.

Found via a 3-agent adversarial review of the previous fix.
2026-09-01 12:00:36 +02:00
Frederic CabassutandClaude Sonnet 5 d4ed358ba3 fix(security): patch dependency CVEs and close SSRF/XSS gaps in MCP image upload
Bumps deps to clear all 69 pnpm audit findings (nodemailer 8->9 for the
raw-option SSRF/arbitrary-file-read CVE; svelte, hono/express/qs chain,
linkify-it, and the rest resolved within their existing semver ranges
via a lockfile refresh). Caps the previously-unbounded cookie override
at <1 so it can't silently jump to the API-incompatible 2.x line again.

Hardens the MCP upload_image tool, which fetched an arbitrary caller-
supplied URL and stored whatever content-type came back with no checks:
- validates every resolved DNS record (not just the first) against
  private/loopback/link-local/multicast ranges, then pins the actual
  connection to the validated address so a second, unvalidated lookup
  at connect time can't be used for DNS-rebinding SSRF
- rejects non-image content-types and enforces the same 10MB cap as
  the manual upload endpoint
- adds X-Content-Type-Options: nosniff to both attachment-serving
  routes as defense in depth

Also validates the admin role field server-side (previously trusted
the client-supplied string), and fixes two incidental regressions
surfaced by the dependency bump: StarterKit now bundles its own
Link/Underline extensions (disabled to avoid duplicate registration),
and FormattingToolbar could call methods on an already-destroyed
editor instance during the markdown-mode toggle race.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 13:43:25 +02:00
Claude 0cc64fd8f3 fix(deps): patch high/critical security advisories
Bumps runtime- and build-reachable dependencies to patched versions and
adds pnpm overrides for transitive advisories. Clears all high/critical
findings (1 critical + 12 high -> 0); remaining moderates/lows are
dev-tooling only and stripped from the production image by pnpm prune.

Direct bumps:
- drizzle-orm ^0.44.7 -> ^0.45.2  (SQL injection via unescaped identifiers, GHSA-gpj5-g38j-94v9)
- @sveltejs/kit ^2.53.4 -> ^2.63.1 (adapter-node BODY_SIZE_LIMIT bypass, GHSA-2crg-3p73-43xp)
- vite ^7.3.1 -> ^7.3.5, vitest/@vitest/coverage-v8 ^3.2.4 -> ^3.2.6 (dev-server file read; vitest UI RCE)

Transitive overrides:
- devalue >=5.8.1   (DoS via sparse-array deserialization, GHSA-77vg-94rm-hx3p)
- path-to-regexp@8 >=8.4.0 (ReDoS via express/router under @modelcontextprotocol/sdk, GHSA-j3q9-mxjg-w52f)
- fast-uri >=3.1.2  (path traversal / host confusion via ajv, GHSA-q3j6-qgpj-74h6)

Verified: pnpm check (0 errors), 264 unit tests pass, production build succeeds.
2026-06-09 21:08:39 +02:00
Frederic CabassutandClaude Sonnet 4.6 80d18478da feat: add theme utility with applyTheme and isDarkMode
Adds src/lib/utils/theme.svelte.ts with applyTheme() (sets data-theme
attribute and meta theme-color) and getIsDarkMode(). Uses a plain
variable instead of $state since Vitest's node environment does not
compile Svelte 5 runes in .svelte.ts files. Adds jsdom dev dependency
and $app/environment alias in vitest config to support DOM-level unit
tests; fixes preferences.test.ts to include the theme default added
in Task 2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 08:47:20 +01:00
Frederic CabassutandClaude Opus 4.6 2798307ed1 feat: add shares service layer with batch fetch and hydration
Create shares-service.ts with fetchSharesForNotes, createShare,
revokeShare, getShareByNoteId, and getSharedNote. Integrate share
tokens into hydrateNotes pipeline alongside tags, attachments,
and collaborators.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 22:06:41 +01:00
Frederic CabassutandClaude Opus 4.6 27e59989b5 fix: register PWA service worker via virtual:pwa-register for offline support
@vite-pwa/sveltekit does not auto-inject SW registration into SSR HTML.
Add explicit registration via virtual:pwa-register in root layout onMount,
inject webmanifest link via virtual:pwa-info, disable SvelteKit's built-in
SW registration to avoid conflicts, and add required dependencies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 20:53:38 +01:00
Claude 57a05bbee0 fix: resolve lost updates in multi-user collaboration sync
Concurrent edits to shared notes (e.g., one user checks a shopping list
item while another adds an item) were lost because the sync system used
whole-document Last-Write-Wins. This replaces it with a 3-way line-level
content merge using node-diff3, so changes to different lines are
preserved from both users.

Key changes:
- Add node-diff3 for 3-way line-level content merging
- Remove the timestamp gate in processSyncPush that rejected entire
  offline sync pushes when another user had updated the note
- Add content merge to both the sync push path and the PATCH endpoint,
  using version snapshots as the merge base
- Send baseVersion from the client so the server can find the correct
  common ancestor for 3-way merge
- Protect pending local fields during client pull merge by reading
  the sync queue and preserving queued-but-unpushed changes
- Add comprehensive tests for content merge, server sync, and CRDT merge

https://claude.ai/code/session_01FNpVBBjM6vKzfR8y9NM9Ci
2026-03-12 20:19:10 +01:00
Frederic CabassutandClaude Opus 4.6 e240f57352 fix: resolve dependabot vulnerabilities — override hono, remove stale package-lock.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:49:57 +01:00
Claude 0b1416908e feat: add email notifications when a note is shared
Send an email to collaborators when they are added to a shared note.
Uses nodemailer with optional SMTP configuration (auto-enabled when
SMTP_HOST is set). Users can opt out via the notifyOnShare preference.

https://claude.ai/code/session_01P4HSMr7QvKw9TMNikUJD9e
2026-03-11 20:33:48 +01:00
Frederic CabassutandClaude Opus 4.6 4ef5dbf20b feat: add code coverage with artifact upload for unit and E2E tests
Add V8 coverage for unit tests via @vitest/coverage-v8 and Istanbul
instrumentation for E2E tests via vite-plugin-istanbul. Coverage data
is collected from browser pages after each Playwright test and merged
with nyc. CI uploads both coverage reports as GitHub Actions artifacts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 09:30:08 +01:00
Frederic CabassutandClaude Opus 4.6 c1e2cf3c8b feat: add table support to TipTap editor
Install @tiptap/extension-table packages, register Table/TableRow/
TableHeader/TableCell extensions, add Table button to the More dropdown
(inserts a 3×3 grid), and style tables to match the parchment theme.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:15:17 +01:00
Frederic CabassutandClaude Opus 4.6 32a3504568 feat: add API keys schema and MCP SDK dependency
- Add `api_keys` table with userId foreign key to schema
- Add `@modelcontextprotocol/sdk` and `zod` dependencies
- Add auto-create SQL and test helpers for api_keys table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 02:03:04 +01:00
Frederic CabassutandClaude Opus 4.6 2c588c6026 chore: regenerate lockfile after rebase onto main
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 01:10:37 +01:00
Frederic CabassutandClaude Opus 4.6 34c95fae92 feat(ui): password strength meter with zxcvbn
Add PasswordStrengthMeter component showing visual bar and feedback.
Integrated in setup, settings change-password, and admin create-user forms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 01:10:37 +01:00
Frederic CabassutandClaude Opus 4.6 e87be60a4b feat: checklist improvements — drag reorder and hide completed
- Add drag-to-reorder via svelte-dnd-action with grip handles
- Add "hide completed" toggle with collapsible done section
- Each checklist item gets a unique ID for stable drag operations
- E2E test for hide/show completed items

Closes #11

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:33:56 +01:00
Frederic CabassutandClaude Opus 4.6 1cfffa1a6e fix: patch transitive dependency vulnerabilities via pnpm overrides
Override serialize-javascript (>=7.0.3), esbuild (<0.25.0 → 0.25.12),
and cookie (>=0.7.0) to resolve Dependabot alerts #1, #2, #3.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 10:18:52 +01:00
Frederic CabassutandClaude Opus 4.6 26b3ae26c3 feat: icon-based formatting toolbar with dropdowns and link popover
Replace plain text toolbar labels with Lucide SVG icons. Group heading,
list, and alignment options into dropdown menus to reduce toolbar width.
Replace window.prompt link insertion with an inline popover (input, apply,
open, remove). Add underline and text-align TipTap extensions. Remove
task list from TipTap editor (broken styling). Fix task list bullet
rendering in note card preview. Increase editor min-height for markdown
mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:50:52 +01:00
Frederic CabassutandClaude Opus 4.6 6a2e54497f feat: replace textarea with TipTap rich text editor
- Add TipTap WYSIWYG editor (headless @tiptap/core) with StarterKit,
  TaskList, TaskItem, Link, Placeholder, and tiptap-markdown extensions
- Always-visible formatting toolbar with undo/redo, H1-H3, bold, italic,
  strikethrough, inline code, code block, blockquote, bullet/ordered/task
  lists, horizontal rule, and link
- Raw markdown toggle for power users
- Render rich text (HTML) on note cards instead of stripped plain text
- Update all e2e tests for TipTap contenteditable editor

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:24:33 +01:00
Frederic CabassutandClaude Opus 4.6 26cae27857 docs: deduplicate README, add OpenAPI spec with auto-generated API docs
- Slim README to essentials, link to docs/ for details
- Add docs/openapi.yaml as single source of truth for the API
- Add scripts/generate-api-docs.ts to produce docs/API.md from the spec
- Add pnpm docs:api / make docs-api target

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:24:29 +01:00
Claude 66c91df983 feat: Crumbs by Bretzel — self-hostable notes app MVP
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 21:16:45 +01:00