The go-sdk Streamable HTTP handler enables DNS-rebinding protection that
rejects any request whose Host header is non-loopback while the server is
bound to a loopback address. memos is commonly run bound to loopback behind a
reverse proxy (e.g. the public demo), so every /mcp request was rejected with
"403 Forbidden: invalid Host header" before authentication ran.
Disable the SDK's localhost protection and rely on memos' own Origin/Host
allowlist (isAllowedMCPOrigin) for CSRF / DNS-rebinding protection. Add a
regression test covering the proxied shape and confirming disallowed origins
are still rejected.
The frontend keyed first-run setup off a null InstanceProfile.admin, but a
null admin only means "no admin-role user exists" — which also happens on a
populated instance that has lost all its admins. Such an instance was wrongly
redirected to signup, where the new account is created as a normal user (the
first-user promotion only triggers when there are zero users), leaving the
instance permanently admin-less.
Add an explicit InstanceProfile.needs_setup derived from user count == 0, and
switch the signup redirect and host tip to use it. admin stays for display only.
Add a rich-text formatting toolbar as the focus-mode header when the
WYSIWYG editor is active: heading dropdown, bold/italic/code, lists, and
link, with a priority+overflow responsive layout and live active-state
highlighting. The toolbar is a self-contained component driven through a
new FormattingController surface routed via EditorContent.
Remove the now-redundant slash-command feature (/todo, /code, /link,
/table) and its "Type / for commands" hint, since the toolbar covers
those actions; the shared suggestion renderer stays for #tag.
Memo detail only showed the first 10 comments: the frontend requested
pageSize=0, which the backend normalizes to DefaultPageSize (10), and the
returned nextPageToken was never followed.
Add useInfiniteMemoComments (mirrors useInfiniteMemos) so the detail page
paginates through every comment, with a "Load more" control in
MemoCommentSection. Page size defaults to DEFAULT_LIST_MEMOS_PAGE_SIZE to
match the memo list convention.
Design system:
- add semantic --success/--warning OKLCH tokens across themes; replace
hardcoded green/amber feedback colors and their manual dark: overrides
- drop the unused @emotion dependency
Kit usage:
- migrate raw <button>/<input> to ui-kit components (actions) or
<div>/<span> (non-action surfaces); keep genuinely custom looks as
raw HTML with their own styles
- make kit usage prop-only (no className overrides): add Button
size="icon-sm", Badge "warning" variant + "pill" shape
- extract a shared Tabs primitive (segmented/underline) and migrate
Inboxes + UserProfile onto it
- tokenize z-index tiers as z-overlay/z-dropdown/z-tooltip
- export variant types (ButtonVariant/Size, BadgeVariant/Shape, TabsVariant)
- document the kit and its policy in components/ui/README.md
- Trim sponsor memo to CodeRabbit + SSD Nodes, concise single-tier layout
- Add a demo personal access token (Bearer memos_pat_demo) for the admin user
- Stagger memo created_ts relative to seed time so the demo timeline always
looks recent; lead the pinned section with the Welcome memo
- Unpin the Scratchpad promo and drop the fixed "June" movie-marathon label
Let users write three more CEL constructs in the filter field, each compiled to
SQL across SQLite/MySQL/Postgres:
- Scalar startsWith()/endsWith() on content/filename/mime_type (case-insensitive)
- matches() regex: PG ~, MySQL/SQLite REGEXP (Go-backed SQLite fn), validated at
compile time via cel.ValidateRegexLiterals()
- all() comprehension over tags via per-element subqueries, non-empty required
Also: contains() now escapes LIKE metacharacters (%, _, \); cross-dialect render
tests plus behavioral tests; cel-go bumped to v0.28.1; new operators surfaced in
the frontend shortcut guide.
Ctrl+A creates a whole-document AllSelection; deleting it (Backspace, Delete, or Cut) maps the AllSelection onto the now-empty paragraph instead of collapsing to a caret, so the view paints a "selected" empty block. A ProseMirror appendTransaction now collapses a leftover AllSelection to a caret after any doc-changing edit.
Reflect any Origin so token-authenticated clients (Access Token V2 / PAT)
can call the API cross-origin, but emit Access-Control-Allow-Credentials
only for trusted origins (same host / configured InstanceURL). This keeps
the SameSite=Lax refresh cookie unreadable by untrusted (incl. same-site
subdomain) origins. Origin: null is not reflected.
Note for operators: cross-origin token access is now open by default; if
you front memos with a caching proxy, ensure it honors `Vary: Origin`.
Extract the Tailwind classes for common markdown elements (paragraph,
blockquote, lists, inline code, link, hr, headings) into a single
markdownStyles.ts consumed by both the read-only MemoContent components
and the WYSIWYG editor, replacing the duplicated per-element strings and
the .memo-wysiwyg CSS block. Heading classes are precomputed per level so
the hot renderHTML path is a lookup, not a cn() merge.
Also require at least one character after `#` before opening the tag
suggestion menu so a bare `#` (or `# ` heading) no longer conflicts with
markdown headings.
Follow-up to #6013. The signing path silently fell back to using the raw
secret string as the HMAC key when a whsec_-prefixed secret had invalid
base64, producing signatures no receiver could verify with no server-side
signal.
- Extract resolveSigningKey helper that errors on invalid whsec_ base64
- Post returns that error (logged by the async dispatcher); ValidateSigningSecret
rejects it at write time so a bad secret is never stored
- Fix stale comment referencing a nonexistent Authorization header
- Add Go tests: key derivation, secret validation, end-to-end signature
round-trip, and the invariant that the secret never leaks into API responses
Add area dropdowns, reproduction requirements, regression info, and
compatibility sections to reduce back-and-forth on bug reports and
feature requests.