| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| | |
|
| | |
|
| |
|
|
|
|
| |
Replace unlimited history claim with honest 90-day retention for
paid tiers. Timeline and search RPCs now filter by tier-appropriate
retention window.
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
| |
Set up BotID bot detection on sensitive API routes (share, billing,
account, webhook-config). Adds client instrumentation, server-side
checkBotId() guards, and withBotId next config wrapper.
Also fix checkout/portal session routes to fall back to request origin
when NEXT_PUBLIC_APP_URL is not set, and center SVG icon properly.
|
| | |
|
| |
|
|
|
|
|
|
|
| |
Add "share" button to text selection toolbar so users can share an entry
with a highlighted passage visible to visitors. The public share page
renders the highlight and scrolls to it on load.
Also fix magic link and password reset redirects to use NEXT_PUBLIC_APP_URL
instead of window.location.origin so emails link to the production domain.
|
| | |
|
| |
|
|
|
|
|
| |
- Use ClipboardItem with Promise to preserve user gesture context
- Fall back to showing share URL in toast if clipboard is unavailable
- Derive app origin from request URL when NEXT_PUBLIC_APP_URL is unset
- Add onError handlers to share/unshare mutations
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
- Fix subscribe_to_feed overload ambiguity by dropping old 4-param version
- Fix vault permission error by using vault.create_secret instead of direct INSERT
- Add duplicate subscription check with clear error message
- Add unmute confirmation dialog matching unsubscribe pattern
- Add feed button in subscriptions settings page
- Add inline rename for feeds, folders, and custom feeds from reader header
- Add drag and drop feeds between folders in sidebar
- Add credential management UI (add/update) for pro/developer tier
- Add add_feed_credentials RPC to convert public feeds to authenticated
- Enable pgsodium extension for vault crypto operations
|
| |
|
|
|
|
|
|
|
|
| |
Wire up the full authenticated feeds pipeline:
- Worker resolves credentials from Supabase Vault for authenticated feeds
- Worker sets owner_id on entries for per-user dedup
- query_param auth now parses name=value format
- Add-feed dialog shows auth type + credential fields for pro/developer
- Subscribe mutation passes credentials to RPC
- Sidebar and settings show [auth] indicator for authenticated feeds
|
| |
|
|
| |
dismisses it
|
| |
|
|
| |
count to right edge
|
| |
|
|
| |
styling and HTML entity decoding
|
| | |
|
| |
|
|
| |
sidebar
|
| |
|
|
| |
delete-all-custom-feeds to danger zone
|
| |
|
|
|
|
| |
Wraps every defaultCache matcher to check sameOrigin first, preventing
the SW from intercepting cross-origin requests (Google favicons,
external images, fonts) which caused no-response errors on redirects.
|
| |
|
|
|
|
| |
Removed static favicon.ico so the dynamic icon.tsx generates the
browser favicon. Added lineHeight: 1 to all icon routes for proper
vertical centering.
|
| |
|
|
|
|
| |
Prevents no-response errors on redirected cross-origin fetches like
Google favicon service by prepending a NetworkOnly rule for all
non-same-origin requests.
|
| |
|
|
|
| |
Install command runs from repo root so pnpm can resolve workspace
packages defined in pnpm-workspace.yaml.
|
| |
|
|
|
|
|
|
|
| |
modal text
Space/Shift+Space now scrolls whichever panel is focused (entry list,
detail panel, or sidebar) instead of only working in the detail panel.
Removed content font setting. Fixed share modal placeholder casing and
ellipsis spacing.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- Space/Shift+Space: page down/up in detail panel (80% scroll)
- Content font: sans-serif/serif/monospace selector in appearance
settings, applied to article content in detail panel
- Accessibility: entry-list-item uses button instead of div, folder
toggles have aria-expanded, shortcut keys have aria-labels
- Share notes: replaced window.prompt with proper modal dialog
matching existing UI patterns
- Worker .env.example: template with all 10 environment variables
- Worker poisoned messages: archive unprocessable queue messages
instead of leaving them stuck forever
- Worker pool Submit: check return value, reschedule dropped feeds
30s into the future, log warnings for rejected submissions
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
- Webhook entry identifier: use entry GUID instead of feed identifier
- Optimistic rollback: add previousTimeline snapshot and onError handler
to both useToggleEntryReadState and useToggleEntrySavedState
- Rate limiter memory leak: delete Map entries when window expires,
use else-if to avoid re-setting after delete
- Entries API limit param: use Number.isFinite guard instead of falsy
coercion that treats 0 as default
- PWA manifest: add PNG raster icon routes (192x192, 512x512) for
devices that don't support SVG icons
- Billing webhook: throw on DB errors and return 500 so Stripe retries
failed events instead of silently losing them
|
| |
|
|
|
|
|
|
| |
- Remove unsafe-eval from script-src CSP (not needed in production)
- Replace Host/Origin header fallback with NEXT_PUBLIC_APP_URL in share
and checkout routes to prevent host header injection
- Add .catch() to request.json() in share POST and PATCH routes
- Add rate limiting (3/min) to account deletion endpoint
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
| |
clamping
Use imperative groupRef API to resize panels instantly instead of
writing to localStorage and calling window.location.reload(). Register
reset callbacks in Zustand store from layout components.
Change sidebarMaxWidth early return from && to || so the generous 35%
fallback is used until both subscriptions and custom feeds have loaded,
preventing intermittent clamping to minimum size.
|
| |
|
|
|
|
| |
Read current panel dimensions from DOM, compute sidebar midpoint
as (192px + maxWidth) / 2, and detail as equal halves. Write
computed values to localStorage before reload.
|
| |
|
|
|
|
| |
Return 35% max until subscriptions/feeds data loads. Previously the
useMemo computed a small max from just nav items on first render,
causing the library to clamp and overwrite the stored sidebar width.
|
| |
|
|
|
|
| |
When sidebar is collapsed, the Group fires onLayoutChanged with only
main-content, overwriting the stored sidebar size. Pass undefined for
onLayoutChanged when collapsed so the stored layout is preserved.
|
| |
|
|
|
|
| |
Rename API key prefix from asn_ to asa_, fix key revoke by aligning
response property names with frontend interface, and add server/client
validation to prevent enabling webhooks without a URL.
|
| |
|
|
|
|
| |
Measures all sidebar items (nav links, feeds, folders, custom feeds,
footer) using Canvas measureText to determine the narrowest width
that avoids truncation, then passes it as the Panel maxSize.
|
| |
|
|
|
|
|
|
| |
The dynamic measurement approach failed because the library caches
Panel constraints at mount and ignores state-driven prop updates.
Now uses fixed rem values (12rem min, 16rem default) which scale
with font size, plus whitespace-nowrap on all sidebar items to
prevent text wrapping at any width.
|
| |
|
|
|
|
| |
querySelectorAll(':scope > *') misses bare text nodes like
'notifications' in the footer button. Now walks childNodes to
handle mixed text node + element children correctly.
|
| |
|
|
|
|
| |
Notifications button text is wider than all entries. Now measures
all nav items AND footer links/buttons, taking the widest row plus
badge reserve as the sidebar minimum width.
|
| |
|
|
|
|
| |
getBoundingClientRect on wrapped text returns the narrow wrapped
width, not the single-line width. Canvas measureText is layout-
independent and gives the true single-line intrinsic text width.
|
| |
|
|
|
|
| |
scrollWidth on a block flex element returns parent width, not content
width. Now sums getBoundingClientRect().width of each child element
(text span + unread badge) for a screen-independent measurement.
|
| |
|
|
|
|
| |
Measures the first sidebar nav item (all entries + unread badge)
after mount and uses its scrollWidth + padding as minSize. Default
is 1.4x the minimum for comfortable reading of feed titles.
|
| |
|
|
|
| |
Without panelIds, the single-panel state (no entry selected) was
overwriting the two-panel layout on every navigation.
|
| |
|
|
|
| |
Wire useDefaultLayout to sidebar Group with localStorage storage.
Update reset command to clear both sidebar and detail layout keys.
|
| |
|
|
|
| |
v4 treats numeric size props as pixels, not percentages.
defaultSize={20} was rendering as 20px (~1.9% of viewport).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
settings
- Rename "muted keywords" to "muted phrases" throughout settings UI
- Add header with navigation to auth pages (sign-in, sign-up, etc.)
- Merge security tab (TOTP setup) into account settings tab
- Fix TOTP name input truncation on Safari (w-64 → flex-1 min-w-0)
- Add appearance settings: font size, time display format, entry images toggle, reading time toggle
- Add keyboard shortcuts dialog (? key) with all keybindings documented
- Add extended vim shortcuts: gg, G, n/N (next/prev unread), Ctrl+h/l (panel focus)
- Add command palette shortcut (⌘K) to shortcuts dialog
- Add icon URL fields for folders and custom feeds (DB + queries + settings UI)
- Add data-has-unreads attribute for sidebar keyboard navigation
- Fix SSR prerendering crash from Zustand persist and react-resizable-panels localStorage access
- Add detail panel layout persistence via useDefaultLayout
- Update marketing copy to advertise vim-like keyboard navigation
|
| |
|
|
|
|
|
|
| |
Comprehensive sweep of all user-facing text to enforce lowercase
convention, including acronyms (api, rest, http, opml, json, totp,
mfa, qr, hmac). Added asa-lowercase/lowercase-strings eslint rule
that reports uppercase in notify() calls, error messages, jsx text,
and checked attributes (placeholder, alt, title).
|
|
|
Full-stack RSS reader SaaS: Supabase + Next.js + Go worker.
Includes three subscription tiers (free/pro/developer), API key auth,
read-only REST API, webhook push notifications, Stripe billing with
proration, and PWA support.
|