<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adrian Fathan</title>
    <description>The latest articles on DEV Community by Adrian Fathan (@adrian_fathan).</description>
    <link>https://dev.to/adrian_fathan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2028005%2F0fb92976-11f1-4775-bcef-3f4d6f9ae9c0.png</url>
      <title>DEV Community: Adrian Fathan</title>
      <link>https://dev.to/adrian_fathan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adrian_fathan"/>
    <language>en</language>
    <item>
      <title>Scraping on the Edge: How I Built a Lightning-Fast Manga Reader with SvelteKit</title>
      <dc:creator>Adrian Fathan</dc:creator>
      <pubDate>Tue, 23 Dec 2025 10:27:34 +0000</pubDate>
      <link>https://dev.to/adrian_fathan/scraping-on-the-edge-how-i-built-a-lightning-fast-manga-reader-with-sveltekit-h8o</link>
      <guid>https://dev.to/adrian_fathan/scraping-on-the-edge-how-i-built-a-lightning-fast-manga-reader-with-sveltekit-h8o</guid>
      <description>&lt;p&gt;As a developer, I have a habit of looking at everyday annoyances and thinking, &lt;em&gt;"I could code my way out of this."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My annoyance? Manga aggregator sites. They are often bloated, riddled with invasive ads, and frustratingly slow on mobile data. I wanted a reading experience that was clean, fast, and simple.&lt;/p&gt;

&lt;p&gt;Instead of complaining, I opened my IDE. I decided to build &lt;strong&gt;FanaCumik&lt;/strong&gt;, an open-source, ad-free manga reader. My goal was twofold: fix my reading experience and, more importantly, learn how to push &lt;strong&gt;SvelteKit&lt;/strong&gt; and &lt;strong&gt;Cloudflare Workers&lt;/strong&gt; to their limits.&lt;/p&gt;

&lt;p&gt;Here is how I built it, the challenges I faced, and how you can contribute.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Tech Stack&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;I chose this stack to ensure maximum performance and zero cost for a hobby project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;SvelteKit:&lt;/strong&gt; For its incredible developer experience and native support for Server-Side Rendering (SSR).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cloudflare Workers:&lt;/strong&gt; To run the scraping logic on the Edge, ensuring low latency for users globally.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cheerio:&lt;/strong&gt; For lightweight, fast HTML parsing.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TailwindCSS:&lt;/strong&gt; To build a mobile-first, app-like UI without writing custom CSS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Architecture: How it Works&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The app doesn't host any content (which keeps it lightweight and legal). Instead, it acts as a smart browser.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;The Request:&lt;/strong&gt; When you click a manga, SvelteKit sends a request to the Cloudflare Worker.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Scrape:&lt;/strong&gt; The worker fetches the HTML from the source (e.g., Asura Scans) and uses &lt;code&gt;Cheerio&lt;/code&gt; to extract only the data we need (title, image links, chapters).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Clean Up:&lt;/strong&gt; All ads, trackers, and unnecessary scripts are discarded.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Delivery:&lt;/strong&gt; The clean JSON data is sent back to the client, where Svelte renders it instantly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Challenge: The Image Proxy&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The biggest technical hurdle was &lt;strong&gt;Hotlink Protection&lt;/strong&gt;. Many manga sites check the &lt;code&gt;Referer&lt;/code&gt; header to ensure images are only loaded on their own domains. If you try to load their image URL directly in your app, it breaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt;&lt;br&gt;
I built a simple proxy endpoint (&lt;code&gt;/api/proxy&lt;/code&gt;).&lt;br&gt;
When the frontend requests an image, it asks my API. My API then fetches the real image while injecting the correct &lt;code&gt;Referer&lt;/code&gt; header to "trick" the source server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Pseudo-code of the logic&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sourceReferer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://original-manga-site.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Referer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sourceReferer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Making it Extensible: The Adapter Pattern&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;I didn't want this to be hard-coded for just one site. I wanted FanaCumik to be a universal reader. I implemented an Adapter pattern where every source is just a class extending a &lt;code&gt;BaseSource&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To add a new site, you only need to write one file. Here is what the implementation for a new source looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NewSource&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseSource&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new-source&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://newsource.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getLatestManga&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/page/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cheerio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// ... scraping logic ...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;mangaList&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This design allows anyone to contribute a new source without touching the core application logic.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Final Thoughts &amp;amp; Future Plans&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Building FanaCumik taught me that &lt;strong&gt;Edge rendering&lt;/strong&gt; is the future of performant web apps. The speed difference compared to client-side fetching is night and day.&lt;/p&gt;

&lt;p&gt;The project is &lt;strong&gt;Open Source&lt;/strong&gt; and available on GitHub.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/MasFana/fana-cumik" rel="noopener noreferrer"&gt;github.com/MasFana/fana-cumik&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://fmo.qzz.io" rel="noopener noreferrer"&gt;fmo.qzz.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am currently looking for contributors! If you know a manga site you’d like to see added, feel free to fork the repo and submit a PR.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This project is for educational purposes only. Please support original creators and official releases where available.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Happy coding! 🦑&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Stop Juggling .env Files: Meet Fana-Envy, a Go-based TTY with Env Manager</title>
      <dc:creator>Adrian Fathan</dc:creator>
      <pubDate>Thu, 18 Dec 2025 22:14:21 +0000</pubDate>
      <link>https://dev.to/adrian_fathan/stop-juggling-env-files-meet-fana-envy-a-go-based-tty-with-env-manager-15np</link>
      <guid>https://dev.to/adrian_fathan/stop-juggling-env-files-meet-fana-envy-a-go-based-tty-with-env-manager-15np</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimlnotsyy8mi1ubbumrx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimlnotsyy8mi1ubbumrx.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Managing environment variables usually involves a mess of &lt;code&gt;export&lt;/code&gt; commands or maintaining a dozen different &lt;code&gt;.env&lt;/code&gt; files that you have to manually source.&lt;/p&gt;

&lt;p&gt;I wanted a better way, so I built Fana-Envy a terminal user interface (TUI) written in Go that handles persistent environments and multiple terminal tabs effortlessly.&lt;/p&gt;

&lt;p&gt;You can Read More, Try or Build from Source here : &lt;a href="https://github.com/MasFana/fana-envy" rel="noopener noreferrer"&gt;https://github.com/MasFana/fana-envy&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>productivity</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Building SvelteMark: A Local-First, Privacy-Focused Markdown Editor with Svelte 5</title>
      <dc:creator>Adrian Fathan</dc:creator>
      <pubDate>Sun, 30 Nov 2025 02:55:34 +0000</pubDate>
      <link>https://dev.to/adrian_fathan/building-sveltemark-a-local-first-privacy-focused-markdown-editor-with-svelte-5-55e1</link>
      <guid>https://dev.to/adrian_fathan/building-sveltemark-a-local-first-privacy-focused-markdown-editor-with-svelte-5-55e1</guid>
      <description>&lt;p&gt;As a developer, I've always been fascinated by the power of tools that enhance productivity while respecting user privacy. That's the philosophy behind &lt;strong&gt;SvelteMark&lt;/strong&gt;, an open-source markdown editor I've just released. Built on the innovative foundation of &lt;strong&gt;Svelte 5&lt;/strong&gt; and its new Runes feature, SvelteMark is not just another markdown editor; it's a commitment to local-first data, privacy, and an exceptional user experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2bzuiaa14kptvljhnfn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2bzuiaa14kptvljhnfn.jpeg" alt="Screenshot of SvelteMark" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Local-First and Privacy-Focused?
&lt;/h3&gt;

&lt;p&gt;In an era where almost every application demands account creation and stores your data in the cloud, I believe there's a need for an alternative. SvelteMark is a response to that need. It's a &lt;strong&gt;100% local-only&lt;/strong&gt; editor, meaning all your notes are securely stored in your browser using IndexedDB. There's no server communication, no tracking, and no account required. Simply open the app, and start writing. Your data, on your device, under your control.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Power of Svelte 5 and Runes
&lt;/h3&gt;

&lt;p&gt;Choosing Svelte 5 for SvelteMark was an easy decision. With its compiler architecture and the introduction of "Runes," Svelte 5 offers an incredibly efficient and intuitive way to build complex web applications. It allowed me to craft a highly responsive and performant user experience. From the seamless live preview to proportional scroll synchronization and tree-based file management, Svelte 5's performance shines through.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features at a Glance
&lt;/h3&gt;

&lt;p&gt;SvelteMark is packed with features designed for writers, developers, and anyone who needs a reliable markdown editor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Local Storage &amp;amp; Security:&lt;/strong&gt; All data in IndexedDB, no server communication, no accounts.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Advanced Core Editor:&lt;/strong&gt; Powered by CodeMirror 6 with syntax highlighting and GitHub-style live preview.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Comprehensive Markdown Support:&lt;/strong&gt; GitHub Flavored Markdown, Math equations (KaTeX), Mermaid diagrams, and code syntax highlighting for 100+ languages.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Intuitive File Management:&lt;/strong&gt; File explorer with nested folders, rename, and delete via context menus.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Polished UI/UX:&lt;/strong&gt; GitHub-inspired dark theme, resizable panels, auto-hide UI, and a view-only mode.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Portable Tools:&lt;/strong&gt; Export/import feature to backup and restore all your notes as JSON.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  See for Yourself!
&lt;/h3&gt;

&lt;p&gt;I invite you to explore SvelteMark and experience a truly local and private markdown writing experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://sm.fana.my.id" rel="noopener noreferrer"&gt;sm.fana.my.id&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting the Code
&lt;/h3&gt;

&lt;p&gt;SvelteMark is an open-source project. If you're interested in seeing the code behind the scenes, contributing, or even just starring it, you can find the repository on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repo:&lt;/strong&gt; &lt;a href="https://github.com/MasFana/sveltemark" rel="noopener noreferrer"&gt;github.com/MasFana/sveltemark&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contributions are highly welcome! Whether it's bug reports, feature requests, or pull requests, your input is invaluable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Building SvelteMark has been a rewarding journey in exploring the frontiers of modern web development and the local-first philosophy. I hope it becomes as useful a tool for you as it was enjoyable for me to create.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and happy writing!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect with me:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/adrianfathan" rel="noopener noreferrer"&gt;linkedin.com/in/adrianfathan&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How I Built a Proof-of-Concept Distributed File Upload System with Next.js 15, UploadThing, and Drizzle ORM</title>
      <dc:creator>Adrian Fathan</dc:creator>
      <pubDate>Thu, 10 Jul 2025 12:40:24 +0000</pubDate>
      <link>https://dev.to/adrian_fathan/how-i-built-a-proof-of-concept-distributed-file-upload-system-with-nextjs-15-uploadthing-and-8o6</link>
      <guid>https://dev.to/adrian_fathan/how-i-built-a-proof-of-concept-distributed-file-upload-system-with-nextjs-15-uploadthing-and-8o6</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1k4g14wqmm11jjus33lt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1k4g14wqmm11jjus33lt.png" alt="Program Screenshot" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was looking for a way to build a &lt;strong&gt;free file upload platform&lt;/strong&gt;, and that's when I discovered &lt;strong&gt;UploadThing&lt;/strong&gt;. However, the default storage limit is quite small just &lt;strong&gt;2GB&lt;/strong&gt;. That limitation inspired me to build a proof-of-concept called &lt;strong&gt;UploadThing RAID&lt;/strong&gt; a &lt;strong&gt;distributed file upload system&lt;/strong&gt; that allows me to bypass that limit by uploading chunks across multiple Accounts.&lt;/p&gt;

&lt;p&gt;I build it using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Next.js 15 (App Router)&lt;/li&gt;
&lt;li&gt;✅ UploadThing for file storage&lt;/li&gt;
&lt;li&gt;✅ Drizzle ORM with SQLite&lt;/li&gt;
&lt;li&gt;✅ Tailwind CSS + TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read the full article : &lt;a href="https://www.linkedin.com/pulse/how-i-built-proof-of-concept-distributed-file-upload-system-imama-xgqgc" rel="noopener noreferrer"&gt;https://www.linkedin.com/pulse/how-i-built-proof-of-concept-distributed-file-upload-system-imama-xgqgc&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Github Image Hosting API with UI</title>
      <dc:creator>Adrian Fathan</dc:creator>
      <pubDate>Mon, 25 Nov 2024 12:02:27 +0000</pubDate>
      <link>https://dev.to/adrian_fathan/github-image-hosting-api-and-with-ui-57f4</link>
      <guid>https://dev.to/adrian_fathan/github-image-hosting-api-and-with-ui-57f4</guid>
      <description>&lt;p&gt;This project is a proof of concept for using a GitHub repository as an image hosting service. The API allows users to upload, list, and delete image files from the repository, providing an easy interface to manage files hosted on GitHub.&lt;/p&gt;

&lt;p&gt;Github : &lt;a href="https://github.com/MasFana/Github-Image-Bucket-API" rel="noopener noreferrer"&gt;MasFana/Github-Image-Bucket-API&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To set up and run this project, you need Node.js and npm installed on your system.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Clone the repository:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/MasFana/Github-Image-Bucket-API
&lt;span class="nb"&gt;cd &lt;/span&gt;Github-Image-Bucket-API

&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install dependencies:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set up environment variables by creating a &lt;code&gt;.env&lt;/code&gt; file in the root directory with the following values:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GITHUB_TOKEN=&amp;lt;your_github_token&amp;gt;
GITHUB_REPO=&amp;lt;your_github_repo&amp;gt;
GITHUB_BRANCH=&amp;lt;your_github_branch&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start the server:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm start

&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The server will run on &lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Environment Variables
&lt;/h2&gt;

&lt;p&gt;The API requires the following environment variables to be set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;GITHUB_TOKEN&lt;/code&gt;: GitHub Personal Access Token for authentication.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;GITHUB_REPO&lt;/code&gt;: GitHub repository name in the format &lt;code&gt;owner/repository&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;GITHUB_BRANCH&lt;/code&gt;: GitHub branch name where files will be uploaded.&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>api</category>
      <category>github</category>
    </item>
    <item>
      <title>Hono Authentication Example App using masfana-mongodb-api-sdk, Cloudflare, and Cloudflare Workers</title>
      <dc:creator>Adrian Fathan</dc:creator>
      <pubDate>Sun, 08 Sep 2024 13:16:07 +0000</pubDate>
      <link>https://dev.to/adrian_fathan/hono-authentication-example-app-using-masfana-mongodb-api-sdk-cloudflare-and-cloudflare-workers-5d6a</link>
      <guid>https://dev.to/adrian_fathan/hono-authentication-example-app-using-masfana-mongodb-api-sdk-cloudflare-and-cloudflare-workers-5d6a</guid>
      <description>&lt;h1&gt;
  
  
  Clone the project : &lt;a href="https://github.com/MasFana/masfana-mongodb-example-auth" rel="noopener noreferrer"&gt;https://github.com/MasFana/masfana-mongodb-example-auth&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;This project is an example of a lightweight authentication system built using the following technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hono Framework&lt;/strong&gt;: A fast web framework for the Edge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;masfana-mongodb-api-sdk&lt;/strong&gt;: A MongoDB API SDK for handling MongoDB operations. &lt;a href="https://www.npmjs.com/package/masfana-mongodb-api-sdk?activeTab=readme" rel="noopener noreferrer"&gt;masfana-mongodb-api-sdk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare Workers&lt;/strong&gt;: Serverless execution environment for running apps at the Edge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hono Sessions&lt;/strong&gt;: Middleware to manage user sessions stored as cookies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Features
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;User registration and login with credentials stored in MongoDB.&lt;/li&gt;
&lt;li&gt;User sessions using cookies, with session expiration.&lt;/li&gt;
&lt;li&gt;Simple protected route example requiring authentication.&lt;/li&gt;
&lt;li&gt;Logout functionality to clear user sessions.&lt;/li&gt;
&lt;li&gt;Deployed on Cloudflare Workers for edge performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;Before running the application, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare Workers Account&lt;/strong&gt;: Set up and configure Cloudflare Workers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB API Key&lt;/strong&gt;: Create an API key and set up the &lt;code&gt;masfana-mongodb-api-sdk&lt;/code&gt; with your MongoDB instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hono Framework&lt;/strong&gt;: This is used to create the web application.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;p&gt;Installation &lt;strong&gt;1. Clone the repository&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone &amp;lt;repository-url&amp;gt;
cd &amp;lt;project-directory&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. Install dependencies&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;If you're using a package manager like &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;yarn&lt;/code&gt;, install the necessary dependencies:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install hono masfana-mongodb-api-sdk hono-sessions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;3. Set up MongoDB connection&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;In your application, replace the MongoDB connection details with your own:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const client = new MongoDBAPI&amp;lt;User&amp;gt;({
  MONGO_API_URL: "your-mongo-api-url",
  MONGO_API_KEY: "your-mongo-api-key",
  DATABASE: "your-database",
  COLLECTION: "your-collection",
  DATA_SOURCE: "your-data-source",
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;4. Deploy to Cloudflare Workers&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;You'll need to configure your Cloudflare Workers environment. Follow the Cloudflare Workers documentation for deployment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Project Structure
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;index.ts&lt;/code&gt;: This file contains the main application logic, including session management, user registration, login, logout, and protected routes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MongoDBAPI&lt;/code&gt;: This is the MongoDB client used to handle CRUD operations with the MongoDB database.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Routes
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Registration Route&lt;/strong&gt; (&lt;code&gt;POST /register&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Allows users to register by providing a username and password.&lt;/li&gt;
&lt;li&gt;Stores user credentials in the MongoDB database.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login Route&lt;/strong&gt; (&lt;code&gt;POST /login&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Verifies user credentials against the MongoDB database.&lt;/li&gt;
&lt;li&gt;If successful, a session is created for the user, storing their ID in a session cookie.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logout Route&lt;/strong&gt; (&lt;code&gt;GET /logout&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Clears the session and logs the user out.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protected Route&lt;/strong&gt; (&lt;code&gt;GET /protected&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Only accessible to authenticated users with an active session.&lt;/li&gt;
&lt;li&gt;Returns a personalized message based on the session data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Home Route&lt;/strong&gt; (&lt;code&gt;GET /&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Displays basic user information and login/registration forms.&lt;/li&gt;
&lt;li&gt;Accessible to both authenticated and non-authenticated users.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Security
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session Management&lt;/strong&gt;: Sessions are managed using the &lt;code&gt;hono-sessions&lt;/code&gt; library, with cookies securely stored and marked as &lt;code&gt;HTTP-only&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption Key&lt;/strong&gt;: Ensure you replace the encryption key with a secure, random string.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Example Usage
&lt;/h1&gt;

&lt;p&gt;Once the app is deployed, users can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Register a new account by entering a username and password.&lt;/li&gt;
&lt;li&gt;Log in using their credentials, which will create a session.&lt;/li&gt;
&lt;li&gt;Access protected content by visiting the protected route, available only after logging in.&lt;/li&gt;
&lt;li&gt;Log out, which will clear their session and log them out of the app.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Deployment
&lt;/h1&gt;

&lt;p&gt;To deploy this application on Cloudflare Workers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up a Cloudflare Workers environment and install Wrangler (&lt;code&gt;npm install -g wrangler&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the application using:&lt;/p&gt;

&lt;p&gt;wrangler publish&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your application will be deployed at your Cloudflare Workers URL, accessible globally.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Using MongoDB with Cloudflare Workers</title>
      <dc:creator>Adrian Fathan</dc:creator>
      <pubDate>Sat, 07 Sep 2024 12:21:59 +0000</pubDate>
      <link>https://dev.to/adrian_fathan/using-mongodb-with-cloudflare-workers-4hie</link>
      <guid>https://dev.to/adrian_fathan/using-mongodb-with-cloudflare-workers-4hie</guid>
      <description>&lt;p&gt;When I tried to create a simple project using Cloudflare Workers and MongoDB, I encountered multiple errors that made the integration process difficult. During my research, I found a few articles that discussed the compatibility issues between MongoDB and Cloudflare Workers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MongoDB and Cloudflare Workers Compatibility Issues&lt;/strong&gt;  I discovered an article titled "&lt;a href="https://www.mongodb.com/community/forums/t/cloudflare-workers-integration-is-now-possible/226708?msockid=3a1f68c701ff620a020e7c4900ba632c" rel="noopener noreferrer"&gt;MongoDB Can't Integrate with Cloudflare Workers&lt;/a&gt;" that highlighted the limitations of using MongoDB with Cloudflare Workers directly. This is primarily due to the Workers' environment, which restricts the use of certain Node.js modules and native MongoDB drivers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Official MongoDB Atlas Data API&lt;/strong&gt;  MongoDB provides an alternative with the Atlas Data API, as described in the article "&lt;a href="https://www.mongodb.com/developer/products/atlas/cloudflare-worker-rest-api/?msockid=3a1f68c701ff620a020e7c4900ba632c" rel="noopener noreferrer"&gt;Create a REST API with Cloudflare Workers and MongoDB Atlas&lt;/a&gt;." This approach uses RESTful API calls to interact with MongoDB Atlas, bypassing the need for native drivers that don't work in the Cloudflare Workers environment.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  My Solution: A TypeScript SDK for MongoDB Atlas Data API
&lt;/h1&gt;

&lt;p&gt;To overcome the integration challenges, I developed an NPM package that simplifies the process. This package is a TypeScript SDK that acts as a wrapper for the MongoDB Atlas Data API, providing type safety and full IntelliSense support for query operators.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/masfana-mongodb-api-sdk" rel="noopener noreferrer"&gt;masfana-mongodb-api-sdk - npm (npmjs.com)&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>cloud</category>
      <category>javascript</category>
      <category>mongodb</category>
    </item>
  </channel>
</rss>
