<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Sabin Shrestha — Knowledge Base</title>
    <link>https://sabinsth.com</link>
    <description>Blog posts, project write-ups, notes, snippets, TIL and case studies from Sabin Shrestha.</description>
    <language>en-us</language>
    <atom:link href="https://sabinsth.com/rss.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Making Stripe Webhook Handlers Idempotent After a Duplicate Purchase Grant</title>
      <link>https://sabinsth.com/til/2026-08-23-stripe-webhook-idempotency</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-08-23-stripe-webhook-idempotency</guid>
      <pubDate>Sun, 23 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL that Stripe can and will deliver the same webhook event more than once, and a handler that reacts to checkout.session.completed by granting access will happily grant it twice — the fix was recording processed event IDs and treating the handler as a set operation, not an append.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Serving Premium Downloads Without Exposing the File&apos;s Real Storage URL</title>
      <link>https://sabinsth.com/til/2026-08-21-presigned-urls-secure-file-downloads</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-08-21-presigned-urls-secure-file-downloads</guid>
      <pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL how to replace a guessable direct-download link with a permission-checked, time-limited presigned URL, so the object storage path a purchased asset actually lives at is never sent to the client.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Server-Sent Events Instead of WebSockets for Live Vote Counts</title>
      <link>https://sabinsth.com/til/2026-08-20-sse-instead-of-websockets-live-vote-counts</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-08-20-sse-instead-of-websockets-live-vote-counts</guid>
      <pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL that live vote tallies only need server-to-client push, not a full-duplex protocol — swapping a hand-rolled WebSocket setup for Server-Sent Events dropped the reconnection logic entirely and simplified the reverse proxy config.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Live Poll Results Without WebSockets: Server-Sent Events in a Node.js API</title>
      <link>https://sabinsth.com/til/2026-08-19-live-poll-results-server-sent-events</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-08-19-live-poll-results-server-sent-events</guid>
      <pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL that once vote writes were race-free, the results screen still felt dead until a manual refresh — switching from client polling to Server-Sent Events made results update instantly without the bidirectional complexity WebSockets would have added for a channel that only ever sends in one direction.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Preventing Duplicate Votes in a Polling API Under Concurrent Requests</title>
      <link>https://sabinsth.com/til/2026-08-18-preventing-duplicate-votes-mongodb</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-08-18-preventing-duplicate-votes-mongodb</guid>
      <pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL that a &apos;check if the user already voted, then write&apos; guard is racy under concurrent requests — the fix was a unique compound index plus an atomic $inc, so MongoDB rejects the duplicate instead of the app trying to catch it first.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>A global color-scheme: dark leaks into print/PDF output unless you override it</title>
      <link>https://sabinsth.com/til/color-scheme-dark-leaks-into-print-pdf</link>
      <guid isPermaLink="true">https://sabinsth.com/til/color-scheme-dark-leaks-into-print-pdf</guid>
      <pubDate>Mon, 17 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL that setting color-scheme: dark once on html/body for a dark-themed site makes the browser paint its default canvas background dark everywhere that property cascades — including print and PDF output — unless @media print resets it.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Webhooks retry, so make the receiver idempotent — not the sender reliable</title>
      <link>https://sabinsth.com/til/webhook-idempotency-deterministic-ids</link>
      <guid isPermaLink="true">https://sabinsth.com/til/webhook-idempotency-deterministic-ids</guid>
      <pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL that webhook delivery is at-least-once, not exactly-once. Instead of trying to prevent duplicate deliveries, derive a deterministic ID from the event and let the receiver refuse to redo work it already did.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Sprout: A Next.js + Supabase Template Where Feedback Writes Its Own Git Branch</title>
      <link>https://sabinsth.com/blog/sprout-feedback-to-git-branch-nextjs-supabase</link>
      <guid isPermaLink="true">https://sabinsth.com/blog/sprout-feedback-to-git-branch-nextjs-supabase</guid>
      <pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate>
      <description>A template that wires a public feedback form straight into GitHub — every submission becomes a git branch via Claude Code, with no human touching the pipeline in between.</description>
      <category>Blog</category>
    </item>
    <item>
      <title>A JSX expression-container attribute silently loses its value in next-mdx-remote</title>
      <link>https://sabinsth.com/til/2026-08-15-mdx-jsx-expression-attributes-lose-value</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-08-15-mdx-jsx-expression-attributes-lose-value</guid>
      <pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL that generating attr={&quot;...&quot;} into MDX source instead of attr=&quot;...&quot; made a prop come back as an empty object on every render, with no error anywhere in the pipeline — found while writing the Obsidian-callout preprocessor for this site.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>One Fuse.js index can search five different content types at once</title>
      <link>https://sabinsth.com/til/fuse-js-search-across-content-collections</link>
      <guid isPermaLink="true">https://sabinsth.com/til/fuse-js-search-across-content-collections</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL that a single flat Fuse.js index with weighted keys is enough to search blog posts, TIL entries, projects, case studies, and snippets together — no separate index or backend needed per collection.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>A Dead WebSocket in a Broadcast List Breaks the Whole Broadcast Loop</title>
      <link>https://sabinsth.com/til/2026-08-13-websocket-broadcast-dead-connections</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-08-13-websocket-broadcast-dead-connections</guid>
      <pubDate>Thu, 13 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL that looping over every connected WebSocket client and sending a message throws on the first one that&apos;s already gone, which silently drops the update for everyone still connected after it in the list — the fix is a try/except per connection, not around the loop.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>A &apos;Hidden&apos; S3 URL Isn&apos;t Access Control — Short-Lived Signed URLs Are</title>
      <link>https://sabinsth.com/til/short-lived-signed-urls-paid-downloads</link>
      <guid isPermaLink="true">https://sabinsth.com/til/short-lived-signed-urls-paid-downloads</guid>
      <pubDate>Wed, 12 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL that a private-looking direct download URL for a purchased file is still a public URL forever, and the fix is generating a signed, expiring link on demand after checking ownership server-side.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>useOptimistic auto-reverts on failure — a hand-rolled optimistic hook doesn&apos;t</title>
      <link>https://sabinsth.com/til/react-use-optimistic-auto-revert</link>
      <guid isPermaLink="true">https://sabinsth.com/til/react-use-optimistic-auto-revert</guid>
      <pubDate>Tue, 11 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL why React&apos;s useOptimistic hook doesn&apos;t need explicit rollback code when a server call fails, while a manual optimistic-update hook built on plain useState does.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>AEO vs SEO, and what I changed here to be more AEO-friendly</title>
      <link>https://sabinsth.com/til/aeo-vs-seo</link>
      <guid isPermaLink="true">https://sabinsth.com/til/aeo-vs-seo</guid>
      <pubDate>Mon, 10 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL: Answer Engine Optimization (AEO) optimizes for being the answer an AI cites, not just ranking in a list of blue links — and most of what makes a Next.js site AEO-friendly is stuff good SEO already wants.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>MutationObserver re-triggers on your own injected DOM — guard against it</title>
      <link>https://sabinsth.com/til/mutationobserver-infinite-loop-injected-ui</link>
      <guid isPermaLink="true">https://sabinsth.com/til/mutationobserver-infinite-loop-injected-ui</guid>
      <pubDate>Mon, 10 Aug 2026 00:00:00 GMT</pubDate>
      <description>TIL a MutationObserver watching a third-party page fires again on the elements your own extension code just injected, causing an infinite injection loop unless the injection function is idempotent.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>nvim-log-insert: A Neovim Plugin That Writes Your console.log Statements For You</title>
      <link>https://sabinsth.com/blog/nvim-log-insert-plugin</link>
      <guid isPermaLink="true">https://sabinsth.com/blog/nvim-log-insert-plugin</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>A tiny Lua plugin that inserts a detailed console.log — file, line number, function, and variable name — with a single leader keymap.</description>
      <category>Blog</category>
    </item>
    <item>
      <title>rrr-stack: The Docker Compose File Behind My Arr Media Server</title>
      <link>https://sabinsth.com/blog/rrr-stack-docker-compose</link>
      <guid isPermaLink="true">https://sabinsth.com/blog/rrr-stack-docker-compose</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>A service-by-service breakdown of rrr-stack, my one-command Docker Compose setup for Jellyseerr, Prowlarr, Sonarr, Radarr, Lidarr, qBittorrent, Jellyfin, Homepage, and Maintainerr.</description>
      <category>Blog</category>
    </item>
    <item>
      <title>Building My Self-Hosted Home Media Server with Docker</title>
      <link>https://sabinsth.com/blog/self-hosted-home-media-server-docker</link>
      <guid isPermaLink="true">https://sabinsth.com/blog/self-hosted-home-media-server-docker</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>A complete walkthrough of my home server — TrueNAS for backups, Proxmox for virtualization, and a fully automated Docker media stack with the *Arr apps and Jellyfin.</description>
      <category>Blog</category>
    </item>
    <item>
      <title>Auth Context for Next.js  (Cookie-Based Sessions)</title>
      <link>https://sabinsth.com/snippets/nextjs-useauth-context</link>
      <guid isPermaLink="true">https://sabinsth.com/snippets/nextjs-useauth-context</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>A React context wrapping an API — login, logout, signup, and password reset — that keeps the client in sync with an httpOnly session cookie by revalidating on mount.</description>
      <category>Snippets</category>
    </item>
    <item>
      <title>Redis-Cached, Server-Clustered Map Pins for a Viewport</title>
      <link>https://sabinsth.com/snippets/redis-clustered-map-pins</link>
      <guid isPermaLink="true">https://sabinsth.com/snippets/redis-clustered-map-pins</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>Serve map pins for whatever bounding box a user is currently viewing, cached in Redis by the exact viewport, with overlapping pins clustered in SQL before they ever leave the server.</description>
      <category>Snippets</category>
    </item>
    <item>
      <title>Clonify.io: Turning a Slow WordPress Marketplace into a High-Performance Next.js SaaS Platform</title>
      <link>https://sabinsth.com/case-studies/clonify-saas-platform</link>
      <guid isPermaLink="true">https://sabinsth.com/case-studies/clonify-saas-platform</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>Rebuilding a digital-products marketplace from WordPress to Next.js and Payload CMS, with a custom JSON caching layer and secure, subscription-aware asset delivery.</description>
      <category>Case Studies</category>
    </item>
    <item>
      <title>Pasal SMS: Building a Digital Business Operating System for Small Businesses</title>
      <link>https://sabinsth.com/case-studies/pasal-sms-business-platform</link>
      <guid isPermaLink="true">https://sabinsth.com/case-studies/pasal-sms-business-platform</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>A multi-tenant SaaS platform on Next.js, Express.js and MongoDB that replaces notebook-and-spreadsheet shop record keeping with digital sales, credit, inventory, and analytics tracking.</description>
      <category>Case Studies</category>
    </item>
    <item>
      <title>Photo Pasal: Building Nepal&apos;s Modern Personalized Gift &amp; Printing Platform</title>
      <link>https://sabinsth.com/case-studies/photo-pasal-gifting-platform</link>
      <guid isPermaLink="true">https://sabinsth.com/case-studies/photo-pasal-gifting-platform</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>Turning a Messenger-and-phone-calls print shop into a scalable Next.js and Payload CMS e-commerce platform for personalized gifting in Nepal.</description>
      <category>Case Studies</category>
    </item>
    <item>
      <title>Pollarise: Building an Interactive Social Polling Platform for Real-Time Community Engagement</title>
      <link>https://sabinsth.com/case-studies/pollarise-social-polling-platform</link>
      <guid isPermaLink="true">https://sabinsth.com/case-studies/pollarise-social-polling-platform</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>A scalable SaaS polling platform on Next.js, Node.js and MongoDB, built to turn opinion-sharing into a fast, social, mobile-first experience rather than a survey form.</description>
      <category>Case Studies</category>
    </item>
    <item>
      <title>Recaho Dispatcher Extension: Engineering a Browser Extension That Streamlined Dispatch Operations</title>
      <link>https://sabinsth.com/case-studies/recaho-dispatcher-extension</link>
      <guid isPermaLink="true">https://sabinsth.com/case-studies/recaho-dispatcher-extension</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>A Chrome extension that injects a live operational dashboard and workflow automation into an existing dispatch platform, with zero backend access or modification.</description>
      <category>Case Studies</category>
    </item>
    <item>
      <title>TeamEnoch.com: Building a High-Performance Business Website with Next.js and a Headless CMS</title>
      <link>https://sabinsth.com/case-studies/teamenoch-website-nextjs-cms</link>
      <guid isPermaLink="true">https://sabinsth.com/case-studies/teamenoch-website-nextjs-cms</guid>
      <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
      <description>Turning a traditional service-business website into an SEO-focused, content-driven Next.js and Payload CMS platform built to generate leads and scale with the business.</description>
      <category>Case Studies</category>
    </item>
    <item>
      <title>Debugging Problems That Only Appear in Production</title>
      <link>https://sabinsth.com/til/2026-06-18-production-only-bugs</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-06-18-production-only-bugs</guid>
      <pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate>
      <description>TIL that a bug I couldn&apos;t reproduce locally turned out to depend on a real difference between environments — request concurrency — that my local setup structurally couldn&apos;t produce, no matter how hard I tried to repro it.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Using Traefik as a Reverse Proxy for a Self-Hosted Stack</title>
      <link>https://sabinsth.com/til/2026-06-13-traefik-reverse-proxy</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-06-13-traefik-reverse-proxy</guid>
      <pubDate>Sat, 13 Jun 2026 00:00:00 GMT</pubDate>
      <description>TIL that manually editing an Nginx config and restarting it for every new service didn&apos;t scale past a handful of containers — Traefik&apos;s label-based routing removed that step entirely by discovering services automatically.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Using Docker for Application Deployment: The Boring Win I Underrated</title>
      <link>https://sabinsth.com/til/2026-06-09-docker-application-deployment</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-06-09-docker-application-deployment</guid>
      <pubDate>Tue, 09 Jun 2026 00:00:00 GMT</pubDate>
      <description>TIL that &apos;works on my machine&apos; stopped being a real category of bug the day I containerized the API, not because Docker is clever but because it removed an entire class of environment-drift I&apos;d been debugging manually.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Using Framer Alongside a Development Workflow, Not Instead of One</title>
      <link>https://sabinsth.com/til/2026-06-06-framer-alongside-development</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-06-06-framer-alongside-development</guid>
      <pubDate>Sat, 06 Jun 2026 00:00:00 GMT</pubDate>
      <description>TIL that building the Clonify Framer plugin taught me Framer is a genuinely different target than a normal web build — its plugin runtime and code-component model don&apos;t map 1:1 onto React conventions.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Turning Figma Designs Into Reusable React Components</title>
      <link>https://sabinsth.com/til/2026-06-02-figma-to-react-components</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-06-02-figma-to-react-components</guid>
      <pubDate>Tue, 02 Jun 2026 00:00:00 GMT</pubDate>
      <description>TIL that building each screen straight from its Figma frame produced pixel-accurate but unreusable components — the fix was designing the component API from the design system&apos;s tokens, not from any one screen.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Designing a Delivery App for Unreliable Networks, Not Just Offline</title>
      <link>https://sabinsth.com/til/2026-05-31-unreliable-mobile-networks</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-05-31-unreliable-mobile-networks</guid>
      <pubDate>Sun, 31 May 2026 00:00:00 GMT</pubDate>
      <description>TIL that &apos;handle offline&apos; undersold the actual problem — the failure mode that hurt drivers most was a flaky, half-connected state, not a clean offline/online boundary.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Choosing Object Storage Instead of the Database for Application Images</title>
      <link>https://sabinsth.com/til/2026-05-26-choosing-object-storage-images</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-05-26-choosing-object-storage-images</guid>
      <pubDate>Tue, 26 May 2026 00:00:00 GMT</pubDate>
      <description>TIL that storing delivery-proof photos as base64 blobs in MongoDB worked fine at low volume and turned into slow queries and ballooning backups once real usage kicked in.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Choosing Node.js Hosting for a SaaS: What Actually Mattered vs. What I Thought Would</title>
      <link>https://sabinsth.com/til/2026-05-23-choosing-nodejs-hosting-saas</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-05-23-choosing-nodejs-hosting-saas</guid>
      <pubDate>Sat, 23 May 2026 00:00:00 GMT</pubDate>
      <description>TIL that I picked Render for a Node.js API expecting the deciding factor to be price, and the thing that actually mattered day to day turned out to be deploy simplicity and predictable cold-start behavior.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Designing a Complete Delivery-Management System as a Solo Developer</title>
      <link>https://sabinsth.com/til/2026-05-19-complete-delivery-management-system</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-05-19-complete-delivery-management-system</guid>
      <pubDate>Tue, 19 May 2026 00:00:00 GMT</pubDate>
      <description>TIL that a system spanning a browser extension, a React Native app, an API, and a database only stayed maintainable solo because I treated the API as the one real product and everything else as a thin client of it.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Building Photo Proof of Delivery: Camera to Dashboard, End to End</title>
      <link>https://sabinsth.com/til/2026-05-16-photo-proof-of-delivery</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-05-16-photo-proof-of-delivery</guid>
      <pubDate>Sat, 16 May 2026 00:00:00 GMT</pubDate>
      <description>TIL that the hard part of a photo-proof-of-delivery feature isn&apos;t the camera or the upload individually — it&apos;s making sure a completed delivery can never end up without its proof attached.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Designing a Dispatch Management Dashboard for Real Operations, Not a Generic Admin Panel</title>
      <link>https://sabinsth.com/til/2026-05-11-dispatch-management-dashboard</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-05-11-dispatch-management-dashboard</guid>
      <pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate>
      <description>TIL that a dispatch dashboard built around &apos;show all the order fields&apos; overwhelmed the person actually using it — the redesign that worked started from what a dispatcher needs to decide, not what data exists.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Writing a Reliable Regex for Extracting Delivery Times</title>
      <link>https://sabinsth.com/til/2026-05-09-regex-delivery-times</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-05-09-regex-delivery-times</guid>
      <pubDate>Sat, 09 May 2026 00:00:00 GMT</pubDate>
      <description>TIL that a regex tuned against a handful of examples (&apos;DELIVERY TIME: 2:00 PM&apos;) broke on real data within a day because of extra whitespace and inconsistent AM/PM casing I hadn&apos;t accounted for.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Extracting Delivery Information from Dynamically Rendered HTML</title>
      <link>https://sabinsth.com/til/2026-05-05-extracting-delivery-info-dynamic-html</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-05-05-extracting-delivery-info-dynamic-html</guid>
      <pubDate>Tue, 05 May 2026 00:00:00 GMT</pubDate>
      <description>TIL that a content script querying the DOM immediately on page load found nothing, because the POS&apos;s order details render client-side, after the content script&apos;s own &apos;document_idle&apos; point had already passed.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Route Handlers can return a plain Response, not just NextResponse</title>
      <link>https://sabinsth.com/til/nextjs-route-handlers-return-plain-responses</link>
      <guid isPermaLink="true">https://sabinsth.com/til/nextjs-route-handlers-return-plain-responses</guid>
      <pubDate>Sun, 03 May 2026 00:00:00 GMT</pubDate>
      <description>TIL you don&apos;t need NextResponse for a simple Route Handler — a standard Web API Response works fine, which matters for things like hand-rolled RSS/XML endpoints.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Recaho Helper Chrome Extension</title>
      <link>https://sabinsth.com/projects/recaho-helper-chrome-extension</link>
      <guid isPermaLink="true">https://sabinsth.com/projects/recaho-helper-chrome-extension</guid>
      <pubDate>Fri, 01 May 2026 00:00:00 GMT</pubDate>
      <description>Browser extension that improves productivity while working inside Recaho.</description>
      <category>Projects</category>
    </item>
    <item>
      <title>Building a POS Integration Without Controlling the POS</title>
      <link>https://sabinsth.com/til/2026-05-01-pos-integration-without-control</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-05-01-pos-integration-without-control</guid>
      <pubDate>Fri, 01 May 2026 00:00:00 GMT</pubDate>
      <description>TIL that integrating with a system you don&apos;t own means designing for its changes, not just its current behavior — the architecture that survived was the one that assumed the POS would break the integration eventually.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Connecting a Chrome Extension to a Node.js API</title>
      <link>https://sabinsth.com/til/2026-04-28-chrome-extension-to-nodejs-api</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-04-28-chrome-extension-to-nodejs-api</guid>
      <pubDate>Tue, 28 Apr 2026 00:00:00 GMT</pubDate>
      <description>TIL that a fetch call from a content script that worked fine in the console failed silently from the actual extension, because content scripts run in an isolated world with their own CORS and CSP rules.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Injecting Custom UI Into a Website You Don&apos;t Own</title>
      <link>https://sabinsth.com/til/2026-04-23-injecting-ui-into-website</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-04-23-injecting-ui-into-website</guid>
      <pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate>
      <description>TIL that a naive injected panel kept getting wiped out by the host page&apos;s own re-renders — the fix was watching for that, not fighting it, and mounting into a container the host page has no reason to touch.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>useDebounce hook</title>
      <link>https://sabinsth.com/snippets/use-debounce-hook</link>
      <guid isPermaLink="true">https://sabinsth.com/snippets/use-debounce-hook</guid>
      <pubDate>Wed, 22 Apr 2026 00:00:00 GMT</pubDate>
      <description>A small generic hook for debouncing a fast-changing value — search inputs, resize handlers, anything you don&apos;t want firing on every keystroke.</description>
      <category>Snippets</category>
    </item>
    <item>
      <title>Reading Data from an Existing Web App with a Chrome Content Script</title>
      <link>https://sabinsth.com/til/2026-04-21-content-script-read-pos-data</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-04-21-content-script-read-pos-data</guid>
      <pubDate>Tue, 21 Apr 2026 00:00:00 GMT</pubDate>
      <description>TIL that a content script reading order data straight from the DOM breaks every time the POS ships a markup change — the fix was reading from the most stable layer available, not the most convenient one.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Building a Chrome Extension with Manifest V3</title>
      <link>https://sabinsth.com/til/2026-04-17-chrome-extension-manifest-v3</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-04-17-chrome-extension-manifest-v3</guid>
      <pubDate>Fri, 17 Apr 2026 00:00:00 GMT</pubDate>
      <description>TIL that MV3&apos;s move from persistent background pages to event-driven service workers means you can&apos;t hold long-lived in-memory state the way old extension tutorials assume — it gets killed and restarted constantly.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>Converting API Timestamps to the User&apos;s Local Time Instead of Hardcoding Dubai Time</title>
      <link>https://sabinsth.com/til/2026-04-14-api-timestamps-local-time</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-04-14-api-timestamps-local-time</guid>
      <pubDate>Tue, 14 Apr 2026 00:00:00 GMT</pubDate>
      <description>TIL that hardcoding a UTC+4 offset for timestamps because most orders happened to be local worked right up until a driver or a server ended up in a different timezone.</description>
      <category>TIL</category>
    </item>
    <item>
      <title>A mental model for Server vs Client Components</title>
      <link>https://sabinsth.com/notes/nextjs-server-client-mental-model</link>
      <guid isPermaLink="true">https://sabinsth.com/notes/nextjs-server-client-mental-model</guid>
      <pubDate>Fri, 10 Apr 2026 00:00:00 GMT</pubDate>
      <description>The rule of thumb I actually use when deciding whether a component needs &apos;use client&apos;, and how a Server Component parent can still pass data down to it.</description>
      <category>Notes</category>
    </item>
    <item>
      <title>Understanding UnknownHostException in Android (and Why the API &apos;Worked Locally&apos;)</title>
      <link>https://sabinsth.com/til/2026-04-10-unknownhostexception-android</link>
      <guid isPermaLink="true">https://sabinsth.com/til/2026-04-10-unknownhostexception-android</guid>
      <pubDate>Fri, 10 Apr 2026 00:00:00 GMT</pubDate>
      <description>TIL that an Android UnknownHostException on a hostname that resolved fine everywhere else usually isn&apos;t a DNS problem at all — it&apos;s the app pointed at a hostname that only ever existed on my dev machine.</description>
      <category>TIL</category>
    </item>
  </channel>
</rss>