<?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>Forem: Uday Rana</title>
    <description>The latest articles on Forem by Uday Rana (@uday-rana).</description>
    <link>https://forem.com/uday-rana</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%2F2016946%2Fee615b96-e126-4c2c-81a1-dec62ef0e432.jpeg</url>
      <title>Forem: Uday Rana</title>
      <link>https://forem.com/uday-rana</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/uday-rana"/>
    <language>en</language>
    <item>
      <title>Remix Vite migration pains</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Tue, 08 Apr 2025 22:15:29 +0000</pubDate>
      <link>https://forem.com/uday-rana/remix-vite-migration-pains-4oep</link>
      <guid>https://forem.com/uday-rana/remix-vite-migration-pains-4oep</guid>
      <description>&lt;p&gt;I've been trying to migrate our project Starchart from Classic Remix Compiler to Remix Vite.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Upgrade Classic Remix Compiler to Remix Vite
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#843&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 20, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;WIP&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;References&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://remix.run/docs/en/main/guides/vite#migrating" rel="nofollow noopener noreferrer"&gt;Remix Vite: Migrating&lt;/a&gt;
&lt;a href="https://www.youtube.com/watch?v=jmNuEEtwkD4" rel="nofollow noopener noreferrer"&gt;How to Fix CJS/ESM Bugs in Remix&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I started a few weeks ago and then gave up because it was too hard. Our custom server is written in TypeScript and I could not figure out how to get it to build and play nice with the Vite build. All of the official examples write the custom server in JavaScript.&lt;/p&gt;

&lt;p&gt;Recently I had another go at it and thanks to &lt;a href="https://github.com/mihaiandrei97/remix-express/" rel="noopener noreferrer"&gt;mihaiandrei97's example setup&lt;/a&gt;, which I found the link to in &lt;a href="https://github.com/remix-run/remix/discussions/6004" rel="noopener noreferrer"&gt;a GitHub discussion&lt;/a&gt;, I did manage to get the server to successfully build and unit tests to pass, but the server would fail during end-to-end tests every now and then, even when changing completely unrelated things like the order of our npm scripts in package.json.&lt;/p&gt;

&lt;p&gt;I also tried the &lt;a href="https://github.com/kiliman/remix-express-vite-plugin" rel="noopener noreferrer"&gt;Remix Express Vite plugin&lt;/a&gt; and couldn't get it to work either - the server just wouldn't start even though the background services did. I noticed the plugin docs said the createServer property accepts an async function as a callback but the types don't allow it. I filed an issue on the repo to get more info.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/kiliman/remix-express-vite-plugin/issues/44" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        createExpressApp.createServer does not accept async function as argument
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#44&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/kiliman/remix-express-vite-plugin/issues/44" rel="noopener noreferrer"&gt;&lt;time&gt;Apr 08, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Hello,&lt;/p&gt;
&lt;p&gt;I want to perform some async operations before starting my server:&lt;/p&gt;
&lt;div class="highlight highlight-source-ts js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-s1"&gt;createServer&lt;/span&gt;: &lt;span class="pl-k"&gt;async&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;app&lt;/span&gt;: &lt;span class="pl-smi"&gt;Application&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;port&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;process&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;env&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;PORT&lt;/span&gt; &lt;span class="pl-c1"&gt;||&lt;/span&gt; &lt;span class="pl-c1"&gt;8080&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

    &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-s1"&gt;services&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;init&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;app&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;listen&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;port&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Based on the &lt;a href="https://github.com/kiliman/remix-express-vite-plugin/tree/main/packages/remix-create-express-app#readme" rel="noopener noreferrer"&gt;README&lt;/a&gt;, createExpressApp.createServer should accept async functions as arguments&lt;/p&gt;
&lt;div class="highlight highlight-source-ts js-code-highlight"&gt;
&lt;pre&gt;createServer?: &lt;span class="pl-k"&gt;async&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;app&lt;/span&gt;: &lt;span class="pl-smi"&gt;Application&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-v"&gt;Server&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;But according to the type definition it doesn't:&lt;/p&gt;
&lt;div class="highlight highlight-source-ts js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;export&lt;/span&gt; &lt;span class="pl-k"&gt;type&lt;/span&gt; &lt;span class="pl-smi"&gt;CreateServerFunction&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;app&lt;/span&gt;: &lt;span class="pl-smi"&gt;Application&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-smi"&gt;Server&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;And instead when trying to pass an async function, I get the error&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Type '(app: Application) =&amp;gt; Promise&amp;lt;Server&amp;lt;typeof IncomingMessage, typeof ServerResponse&amp;gt;&amp;gt;' is not assignable to type 'CreateServerFunction'.
  Type 'Promise&amp;lt;Server&amp;lt;typeof IncomingMessage, typeof ServerResponse&amp;gt;&amp;gt;' is missing the following properties from type 'Server': listen, close, address, getConnections, and 21 more.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Are async functions not supported or is the type wrong?&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kiliman/remix-express-vite-plugin/issues/44" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;So with that ruled out the only solutions I could think of were to either run the server with tsx as mentioned in &lt;a href="https://remix.run/blog/remix-heart-vite" rel="noopener noreferrer"&gt;Remix's blog&lt;/a&gt; or to convert our custom server to JavaScript, like their examples.&lt;/p&gt;

&lt;p&gt;While I wait to hear back from the others on what they think the better approach is, I'm going to switch gears and work on the other issue for this sprint, which is looking into passkey encryption for users' API keys in our other project chatcraft.org.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/872" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Encrypt users' API keys with passkeys
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#872&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/872" rel="noopener noreferrer"&gt;&lt;time&gt;Apr 06, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Earlier this week &lt;a class="mentioned-user" href="https://dev.to/humphd"&gt;@humphd&lt;/a&gt; suggested encrypting users' API keys with passkeys using &lt;a href="https://github.com/FiloSottile/typage" rel="noopener noreferrer"&gt;age-encryption&lt;/a&gt;, which will eventually let us store them in the backend.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/872" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Planning the Last Sprint</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Thu, 03 Apr 2025 18:11:51 +0000</pubDate>
      <link>https://forem.com/uday-rana/planning-the-last-sprint-50pm</link>
      <guid>https://forem.com/uday-rana/planning-the-last-sprint-50pm</guid>
      <description>&lt;p&gt;For this last sprint in OSD700, there are two things I want to work on. &lt;/p&gt;

&lt;h2&gt;
  
  
  Starchart
&lt;/h2&gt;

&lt;p&gt;For &lt;a href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;Starchart&lt;/a&gt;, I want to try and finish the migration I was working on from Classic Remix Compiler to Remix Vite, so that we can include it in the release next week.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Upgrade Classic Remix Compiler to Remix Vite
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#843&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 20, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;WIP&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;References&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://remix.run/docs/en/main/guides/vite#migrating" rel="nofollow noopener noreferrer"&gt;Remix Vite: Migrating&lt;/a&gt;
&lt;a href="https://www.youtube.com/watch?v=jmNuEEtwkD4" rel="nofollow noopener noreferrer"&gt;How to Fix CJS/ESM Bugs in Remix&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Last I worked on it, I managed to get the dev server to run fine, but something's still broken in the build step, because the server gets stuck starting up forever after being built.&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%2F9krprels9urgjpeimuyg.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%2F9krprels9urgjpeimuyg.png" alt="CI timeout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm not sure how to debug this yet but I'd really like to get it in as part of the release so I expect to spent a fair amount of time on it this week.&lt;/p&gt;

&lt;h2&gt;
  
  
  chatcraft.org
&lt;/h2&gt;

&lt;p&gt;The other thing I'm doing for this sprint is looking into implementing &lt;a href="https://github.com/FiloSottile/typage" rel="noopener noreferrer"&gt;age encryption&lt;/a&gt; for API keys in &lt;a href="https://github.com/tarasglek/chatcraft.org" rel="noopener noreferrer"&gt;chatcraft.org&lt;/a&gt;, which will allow for securely storing them on the server instead of in browser storage. This should be pretty interesting because I haven't had a lot of opportunities to write new code this term, and I'll have to do some research into the implementation since I haven't worked with age encryption before.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Fixing a regression with git bisect</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Sun, 30 Mar 2025 00:14:45 +0000</pubDate>
      <link>https://forem.com/uday-rana/taking-git-bisect-for-a-spin-c05</link>
      <guid>https://forem.com/uday-rana/taking-git-bisect-for-a-spin-c05</guid>
      <description>&lt;p&gt;This sprint I worked on &lt;a href="https://github.com/tarasglek/chatcraft.org" rel="noopener noreferrer"&gt;chatcraft.org&lt;/a&gt; where I had the opportunity to fix a regression using git bisect for the first time.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/tarasglek" rel="noopener noreferrer"&gt;
        tarasglek
      &lt;/a&gt; / &lt;a href="https://github.com/tarasglek/chatcraft.org" rel="noopener noreferrer"&gt;
        chatcraft.org
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Developer-oriented ChatGPT clone
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;ChatCraft.org&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Welcome to &lt;a href="https://chatcraft.org" rel="nofollow noopener noreferrer"&gt;ChatCraft.org&lt;/a&gt;, your open-source web companion for coding with Large Language Models (LLMs). Designed with developers in mind, ChatCraft transforms the way you interact with GPT models, making it effortless to read, write, debug, and enhance your code.&lt;/p&gt;
&lt;p&gt;Whether you're exploring new designs or learning about the latest technologies, ChatCraft is your go-to platform. With a user interface inspired by GitHub, and editable Markdown everywhere, you'll feel right at home from the get-go.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/docs/chatcraft-example.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftarasglek%2Fchatcraft.org%2Fdocs%2Fchatcraft-example.png" alt="ChatCraft UI Example"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;We think ChatCraft is the best platform for learning, experimenting, and getting creative with code. Here's a few of the reasons why we think you'll agree:&lt;/p&gt;
&lt;p&gt;🛠️ &lt;strong&gt;You're in Control&lt;/strong&gt;: Customize all aspects of a chat. Use your own System Prompts, edit, delete, and retry AI messages with models from competing vendors in the same chat.&lt;/p&gt;
&lt;p&gt;🌍 &lt;strong&gt;Multiple AI Providers&lt;/strong&gt;: ChatCraft supports both OpenAI and OpenRouter, giving you access to a…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Issue 1
&lt;/h2&gt;

&lt;p&gt;I mostly spent time looking into this issue which listed a number of bugs in the user settings modal:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/848" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        openrouter mostly broken in settings
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#848&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/tarasglek" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F857083%3Fv%3D4" alt="tarasglek avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/tarasglek" rel="noopener noreferrer"&gt;tarasglek&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/848" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 04, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;For repro&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;use chatcraft.org in private window.&lt;/li&gt;
&lt;li&gt;open settings&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Click on checkbox next to openrouter&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;it selects openai&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Click on openrouter api key box&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;It now shows up the magic "get openrouter key" box...We should probably surface that better&lt;/li&gt;
&lt;li&gt;Click it, login&lt;/li&gt;
&lt;li&gt;Observe how openrouter key was not added&lt;/li&gt;
&lt;/ol&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/848" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This issue outlined three bugs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clicking any of the checkboxes for choosing the LLM provider in the settings modal would always result in the first provider being selected.&lt;/li&gt;
&lt;li&gt;The "Get OpenRouter Key" button would only show when the API key input field was focused, which was bad for the option's discoverability.&lt;/li&gt;
&lt;li&gt;The button doesn't actually work.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Bug 1: Broken LLM selection in settings
&lt;/h3&gt;

&lt;p&gt;I spent two days looking into this bug. I had a hunch it was a regression because I figured surely the UI for this must have worked at some point, but there hadn't been any recent changes to the component. I tried to investigate by checking out the last commit that touched the LLM selection code, but I ran into errors installing the dependencies. pnpm said it couldn't find the dependencies, which I assume was because the versions were just that old.&lt;/p&gt;

&lt;p&gt;After that I gave up on the regression idea (in hindsight, I should've kept digging) and instead tried looking into the current code. I had no luck trying to debug the existing logic, so I tried to re-create the component from scratch. I noticed it worked until I wrapped the &lt;code&gt;&amp;lt;Table&amp;gt;&lt;/code&gt; element which contains the checkboxes in a &lt;code&gt;&amp;lt;FormControl&amp;gt;&lt;/code&gt;, both of these being Chakra UI components. So I figured the bug must be in the JSX being rendered and not in the component logic, but again, there hadn't been any recent changes to the JSX.&lt;/p&gt;

&lt;p&gt;Since we were using Chakra UI I wondered if the behaviour of the components we were using might have changed, so I tried finding a commit without the bug again. I checked out a random commit from this past September and built and ran the app, and sure enough, the bug wasn't there, which confirmed that this was a regression.&lt;/p&gt;

&lt;p&gt;This meant I finally had an opportunity to use &lt;a href="https://git-scm.com/docs/git-bisect" rel="noopener noreferrer"&gt;git bisect&lt;/a&gt; to find the commit that caused the bug. git bisect is a git command that uses binary search to identify which commit introduced a bug in your program. I was excited to try it out, and it led me to this commit which updated a bunch of dependencies:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/847" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Update deps for March 2025
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#847&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/humphd" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F427398%3Fv%3D4" alt="humphd avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/humphd" rel="noopener noreferrer"&gt;humphd&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/847" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 02, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Updating deps for March, most things are easy, but I had to leave &lt;code&gt;apache-arrow&lt;/code&gt; at 17 vs. 19 for duckdb compat, and the new TypeScript isn't compatible with eslint yet (PR hasn't landed).  The rest is probably fine to leave.&lt;/p&gt;
&lt;p&gt;Please test and make sure this works for you.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/847" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The most obvious suspect was Chakra UI being bumped from 2.10.5 to 2.10.6. I tested with 2.10.5 and the bug wasn't there - then, I installed 2.10.6, and it stopped working, which confirmed my suspicions. I tried looking for release notes for this version, but there weren't any - not on GitHub, and not on their website. I went to their issues page on GitHub and searched for "2.10.5" which led me to this issue:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/chakra-ui/chakra-ui/issues/9747" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        CheckboxGroup breaks when wrapped by FormControl: Electric Boogaloo
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#9747&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/EmilRybergAkson" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F137047672%3Fv%3D4" alt="EmilRybergAkson avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/EmilRybergAkson" rel="noopener noreferrer"&gt;EmilRybergAkson&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/chakra-ui/chakra-ui/issues/9747" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 28, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Description&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Seems like the same bug from #8938 has reappeared in 2.10.6.
2.10.3-2.10.5 all work.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Link to Reproduction&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://codesandbox.io/p/devbox/wonderful-dan-forked-yl6kxl" rel="nofollow noopener noreferrer"&gt;https://codesandbox.io/p/devbox/wonderful-dan-forked-yl6kxl&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Chakra UI Version&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;2.10.6&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Browser&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Google Chrome 133&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Operating System&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;[ ] macOS&lt;/li&gt;
&lt;li&gt;[x] Windows&lt;/li&gt;
&lt;li&gt;[ ] Linux&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/chakra-ui/chakra-ui/issues/9747" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;One of the maintainers of Chakra UI commented on this saying that this was patched in 2.10.7, so I updated to it and the bug was fixed.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/865" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Fix LLM provider selection bug
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#865&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/865" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 28, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Related issue: #848&lt;/p&gt;
&lt;p&gt;I was able to bisect the selection issue to &lt;a href="https://github.com/tarasglek/chatcraft.org/commit/682acced4bde6a5d1289be3df1142969fb046090" rel="noopener noreferrer"&gt;https://github.com/tarasglek/chatcraft.org/commit/682acced4bde6a5d1289be3df1142969fb046090&lt;/a&gt; (&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/847" rel="noopener noreferrer"&gt;https://github.com/tarasglek/chatcraft.org/pull/847&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The bug originated when updating &lt;code&gt;@chakra-ui/react&lt;/code&gt; from 2.10.5 to 2.10.6. An issue was filed for this bug at &lt;a href="https://github.com/chakra-ui/chakra-ui/issues/9747" rel="noopener noreferrer"&gt;https://github.com/chakra-ui/chakra-ui/issues/9747&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This issue was addressed in 2.10.7. Upgrading fixes the problem.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/865" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Even though the fix ultimately ended up being really simple, I'm glad I knew about git bisect because I don't think I could have found the cause of this bug without it. I probably would've kept looking for potentially breaking changes in the settings component or related components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug 2: "Get OpenRouter Key" button only shows when OpenRouter API key field is focused
&lt;/h3&gt;

&lt;p&gt;I'm not sure if this counts as a bug since this was an intentional decision, but I think making the button always visible is a good idea so users can find out that option exists in the first place. To do this, I just had to remove a condition that checked whether the API key field was focused before displaying it. I finished this before the selection bug and made a separate pull request since I wasn't sure at the time whether I'd be able to fix that one.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/864" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        In User Settings &amp;gt; Models &amp;gt; LLM Providers, show "Get OpenRouter Key" button even when OpenRouter is not selected
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#864&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/864" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 28, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Related: #848&lt;/p&gt;
&lt;p&gt;Button still doesn't actually get the key but I figured this might be worth landing separately&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/864" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The third bug, the button not working, is something I didn't have time to work on this sprint. It might be worth investigating next sprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 2
&lt;/h2&gt;

&lt;p&gt;Although well overdue, I finished the issue I signed up for last sprint, which was refactoring the program to use the new &lt;code&gt;useChat&lt;/code&gt; custom React hook.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/835" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Refactor Code To Use `useChat()` Hook
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#835&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/mulla028" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F138519917%3Fv%3D4" alt="mulla028 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/mulla028" rel="noopener noreferrer"&gt;mulla028&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/835" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 20, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Description&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Since &lt;a class="mentioned-user" href="https://dev.to/humphd"&gt;@humphd&lt;/a&gt; landed #822, introduced &lt;code&gt;ChatProvider&lt;/code&gt; &amp;amp; &lt;code&gt;useChat()&lt;/code&gt; hook. We need to refactor code to stop passing &lt;code&gt;chat&lt;/code&gt; on &lt;code&gt;props&lt;/code&gt; in components and utilize &lt;code&gt;useChat()&lt;/code&gt; hook wherever it's possible .&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/835" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I spent a while trying to fit the hook into places where it didn't make sense and in the end only found one place where using it did make sense. The hook gets a &lt;code&gt;chat&lt;/code&gt; object by getting it's ID from the route parameter and making a database query, but most components in the code receive the chat through props from two higher-level components. Those higher-level components get &lt;code&gt;chat&lt;/code&gt; using React Router's &lt;code&gt;loader&lt;/code&gt; function, meaning I couldn't swap their logic out for the hook without making the code more complicated which would defeat the purpose of the refactor. Even if I did, we'd still need to drill the chat prop to their child components, because the logic for chat being undefined is only handled in the higher-level components and handling it at every level would once again just make the code messier.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/860" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Use useChat in MessageBase.tsx
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#860&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/860" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 26, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Fixes #835&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;useChat&lt;/code&gt; hook can't be used in any components that are children of &lt;code&gt;ChatBase&lt;/code&gt;. &lt;code&gt;ChatBase&lt;/code&gt; receives the &lt;code&gt;chat&lt;/code&gt; prop from it's parent components &lt;code&gt;LocalChat&lt;/code&gt; and &lt;code&gt;RemoteChat&lt;/code&gt;. These components retrieve &lt;code&gt;chat&lt;/code&gt; using &lt;code&gt;useLoaderData()&lt;/code&gt;, while the hook retrieves &lt;code&gt;chat&lt;/code&gt; from the route parameter using &lt;code&gt;useParams()&lt;/code&gt;. From what I understand, this means the hook can't replace the usage in &lt;code&gt;LocalChat&lt;/code&gt; and &lt;code&gt;RemoteChat&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This leaves &lt;code&gt;MessageBase&lt;/code&gt; as the only component where &lt;code&gt;useChat&lt;/code&gt; can be used in it's current implementation.&lt;/p&gt;
&lt;p&gt;Using the hook in &lt;code&gt;LocalChat&lt;/code&gt; and &lt;code&gt;RemoteChat&lt;/code&gt; will require refactoring them and their usage in &lt;code&gt;router.tsx&lt;/code&gt;. I'll try this and see if it makes sense to do this.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/860" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Extra
&lt;/h2&gt;

&lt;p&gt;I also tried looking into this issue until I noticed it had already been fixed and just wasn't closed:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/855" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add email to GitHub token info
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#855&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/humphd" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F427398%3Fv%3D4" alt="humphd avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/humphd" rel="noopener noreferrer"&gt;humphd&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/855" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 12, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;When a user logs in, we need to also grab the email for the user and include in the data.  The Google auth function already does this.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/855" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;There was a typo mentioned in one of the comments on the issue which wasn't fixed, so I went ahead and fixed that while I was working on the other stuff.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/861" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Fix "ouath" typo
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#861&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/861" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 27, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      
    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/861" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Progress Update</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Thu, 13 Mar 2025 14:54:35 +0000</pubDate>
      <link>https://forem.com/uday-rana/progress-update-4lo4</link>
      <guid>https://forem.com/uday-rana/progress-update-4lo4</guid>
      <description>&lt;p&gt;I wasn't able to get as much done this sprint as I hoped. Here's what I did:&lt;/p&gt;

&lt;h2&gt;
  
  
  chatcraft.org
&lt;/h2&gt;

&lt;p&gt;I tried doing some work in chatcraft.org but got stuck. I was trying to refactor the code to use a custom hook to manage state instead of prop drilling.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/835" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Refactor Code To Use `useChat()` Hook
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#835&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/mulla028" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F138519917%3Fv%3D4" alt="mulla028 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/mulla028" rel="noopener noreferrer"&gt;mulla028&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/835" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 20, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Description&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Since @humphd landed #822, introduced &lt;code&gt;ChatProvider&lt;/code&gt; &amp;amp; &lt;code&gt;useChat()&lt;/code&gt; hook. We need to refactor code to stop passing &lt;code&gt;chat&lt;/code&gt; on &lt;code&gt;props&lt;/code&gt; in components and utilize &lt;code&gt;useChat()&lt;/code&gt; hook wherever it's possible .&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/835" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Unfortunately I ran into some trouble with the types. The hook can potentially return undefined, which the code doesn't handle, since when it's being passed through props that's not something that needs to be handled.&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%2Fykh60a6hviuojjicq4mj.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%2Fykh60a6hviuojjicq4mj.png" alt="Image description" width="800" height="48"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'll need to dedicate some more time to this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mattermost
&lt;/h2&gt;

&lt;p&gt;I did some fixes on my PR in Mattermost.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/mattermost/mattermost/pull/29414" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        [MM-53650] Add disable emoticon rendering setting to webapp
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#29414&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/mattermost/mattermost/pull/29414" rel="noopener noreferrer"&gt;&lt;time&gt;Nov 28, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Summary&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;This pull request adds a user setting to the webapp to toggle rendering emoticons (&lt;code&gt;:D&lt;/code&gt;) as emojis (😄).&lt;/p&gt;
&lt;p&gt;The setting is added as a component in &lt;code&gt;components/user_settings/display/render_emoticons_as_emoji/&lt;/code&gt; which is imported in &lt;code&gt;components/user_settings/display/user_settings_display.tsx&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I've added a &lt;code&gt;renderOnOffLabel()&lt;/code&gt; function to &lt;code&gt;user_settings_display.tsx&lt;/code&gt;, lifted from &lt;code&gt;components/user_settings/advanced/user_settings_advanced.tsx&lt;/code&gt; to help render the new component.&lt;/p&gt;
&lt;p&gt;The setting is stored as a user preference using the &lt;code&gt;savePreferences()&lt;/code&gt; action.&lt;/p&gt;
&lt;p&gt;I've added constants for the preference to &lt;code&gt;utils/constants.tsx&lt;/code&gt; and &lt;code&gt;webapp/channels/src/packages/mattermost-redux/src/constants/preferences.ts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To actually use the setting, I've modified &lt;code&gt;components/post_markdown&lt;/code&gt; to receive it's value as a prop, for which I've used &lt;code&gt;getBool()&lt;/code&gt; and added a default value to the config. &lt;code&gt;post_markdown&lt;/code&gt; passes this value down to &lt;code&gt;Markdown&lt;/code&gt; on the &lt;code&gt;options&lt;/code&gt; object, which then passes it down to &lt;code&gt;utils/text_formatting.tsx&lt;/code&gt;, which finally passes the value to &lt;code&gt;emoticons.tsx&lt;/code&gt; as a newly added parameter. &lt;code&gt;emoticons.tsx&lt;/code&gt; checks whether the value is true and if it is, it transforms the emoticons into emojis.&lt;/p&gt;
&lt;p&gt;I've updated affected tests and created unit tests for the new component. I've also updated the English translation file.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h5 class="heading-element"&gt;QA Test Steps&lt;/h5&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to User Settings.&lt;/li&gt;
&lt;li&gt;Go to the Display category.&lt;/li&gt;
&lt;li&gt;Find the section labelled "Auto-render emoticons as emoji" and click "Edit".&lt;/li&gt;
&lt;li&gt;Toggle the setting and click "Save".&lt;/li&gt;
&lt;li&gt;Emoticon rendering on messages sent by the current user and other users should be toggled client-side with the setting.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Ticket Link&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Fixes (partially) &lt;a href="https://github.com/mattermost/mattermost/issues/26504" rel="noopener noreferrer"&gt;https://github.com/mattermost/mattermost/issues/26504&lt;/a&gt;
Jira &lt;a href="https://mattermost.atlassian.net/browse/MM-53650" rel="nofollow noopener noreferrer"&gt;https://mattermost.atlassian.net/browse/MM-53650&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; the issue and ticket describe adding this feature to the mobile app as well, which this PR does not.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Screenshots&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;before&lt;/th&gt;
&lt;th&gt;after&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer" href="https://github.com/user-attachments/assets/17600204-6446-4206-ab86-a8aea7ed05b3"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2F17600204-6446-4206-ab86-a8aea7ed05b3" alt="image"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer" href="https://github.com/user-attachments/assets/cc7ac7bf-1eb8-47c5-bb93-abce42bc006a"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2Fcc7ac7bf-1eb8-47c5-bb93-abce42bc006a" alt="image"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Release Note&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;pre&gt;&lt;code&gt;Added a new user setting to toggle rendering emoticons (:D) as emojis (😄)
&lt;/code&gt;&lt;/pre&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mattermost/mattermost/pull/29414" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The useEffect callback in my component sets focus on a link within the component, but it's supposed to be called when the component is interacted with instead of on the initial render. As it was, as soon as the component was rendered, it would focus on the link, meaning the page would scroll down to the component instead of starting at the top. The maintainers caught this bug and recommended I use a hook they wrote, which as far as I understand, works like useEffect but skips the initial render.&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%2Fuq9tckpt9f4suqc3yxm9.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%2Fuq9tckpt9f4suqc3yxm9.png" alt="Image description" width="800" height="637"&gt;&lt;/a&gt;&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%2Fdwyeddsymerh54hln5sk.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%2Fdwyeddsymerh54hln5sk.png" alt="Image description" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I switched from useEffect to their hook and re-requested a review.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Back to Work</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Thu, 06 Mar 2025 05:08:14 +0000</pubDate>
      <link>https://forem.com/uday-rana/back-to-work-2m3i</link>
      <guid>https://forem.com/uday-rana/back-to-work-2m3i</guid>
      <description>&lt;p&gt;I've been spending my break away from the computer and so I haven't worked on Starchart in a minute. Here's the latest and what I want to do next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pull Requests
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;MX Record support:&lt;/strong&gt; This was the big feature I planned to work on but didn't get to. My team member Theo took the initiative on this so I'm going to work with him to see this through.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/852" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add ability to handle MX records
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#852&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/theoforger" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F173939954%3Fv%3D4" alt="theoforger avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/theoforger" rel="noopener noreferrer"&gt;theoforger&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/852" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 04, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Closes #787.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Description&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;This PR implements the feature to manage MX records. It also includes relevant unit tests and a new section in the instructions page.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;References&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html#MXFormat" rel="nofollow noopener noreferrer"&gt;Supported DNS record types - MX record type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc2181#section-10.3" rel="nofollow noopener noreferrer"&gt;RFC 2181 - 10.3. MX and NS records&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/852" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Remix Vite migration:&lt;/strong&gt; I was in the middle of working on this the last time I worked on Starchart, but there were many, many breaking changes and it proved quite overwhelming. I found &lt;a href="https://alemtuzlak.hashnode.dev/migrating-a-v1-cjs-remix-project-to-remix-vite-esm" rel="noopener noreferrer"&gt;a blog&lt;/a&gt; detailing somebody else's experience migrating to Remix Vite, so I'm going to spend some more time and see if I can figure this out.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Upgrade Classic Remix Compiler to Remix Vite
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#843&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 20, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;WIP&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;References&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://remix.run/docs/en/main/guides/vite#migrating" rel="nofollow noopener noreferrer"&gt;Remix Vite: Migrating&lt;/a&gt;
&lt;a href="https://www.youtube.com/watch?v=jmNuEEtwkD4" rel="nofollow noopener noreferrer"&gt;How to Fix CJS/ESM Bugs in Remix&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In the meantime, I've filed a pull request for an intermediate step - moving from &lt;code&gt;remix watch&lt;/code&gt; to &lt;code&gt;remix dev&lt;/code&gt;. This makes our npm scripts a lot simpler:&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%2Fh1pjyvbtuph0v1kpwde7.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%2Fh1pjyvbtuph0v1kpwde7.png" alt="Image description" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/842" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Upgrade `remix watch` to `remix dev`
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#842&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/842" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 20, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;This is an intermediate step in upgrading to Remix Vite.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Changes&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Upgrade &lt;code&gt;remix watch&lt;/code&gt; to &lt;code&gt;remix dev&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;We were supposed to do this when upgrading to v2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;tsx&lt;/code&gt; to run &lt;code&gt;server.ts&lt;/code&gt; and watch for changes instead of building it first with &lt;code&gt;esbuild&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Remix examples use a .js file for the server so I went to the Remix Discord server and they recommended this method. However, this is slower than building the server.&lt;/li&gt;
&lt;li&gt;We no longer need &lt;code&gt;predev&lt;/code&gt;, &lt;code&gt;dev:build&lt;/code&gt;, &lt;code&gt;delay&lt;/code&gt;, &lt;code&gt;dev:remix&lt;/code&gt;, &lt;code&gt;dev:server:delay&lt;/code&gt;, &lt;code&gt;dev:server&lt;/code&gt; scripts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Remove &lt;code&gt;purgeRequireCache&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;According to the video walkthrough linked below this is no longer required.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Remove &lt;code&gt;--require ./node_modules/dotenv/config&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;According to the video walkthrough linked below, this is no longer required because Remix automatically loads &lt;code&gt;.env&lt;/code&gt; files.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;ts-node&lt;/code&gt; with &lt;code&gt;tsx&lt;/code&gt; in &lt;code&gt;prisma.seed&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;We already had &lt;code&gt;ts-node&lt;/code&gt; to run TypeScript files, but Remix recommends &lt;code&gt;tsx&lt;/code&gt; and there's no reason to keep both&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;References&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://remix.run/docs/en/main/start/v2#custom-app-server" rel="nofollow noopener noreferrer"&gt;Upgrading to v2: &lt;code&gt;remix dev&lt;/code&gt;: Custom app server&lt;/a&gt;
&lt;a href="https://remix.run/docs/en/main/other-api/dev#with-custom-app-server" rel="nofollow noopener noreferrer"&gt;@remix-run/dev CLI: &lt;code&gt;remix dev&lt;/code&gt;: With custom app server&lt;/a&gt;
&lt;a href="https://www.youtube.com/watch?v=6jTL8GGbIuc" rel="nofollow noopener noreferrer"&gt;Migrating your project to v2_dev 🚚&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/842" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Issues filed
&lt;/h2&gt;

&lt;p&gt;I filed a couple of issues - one for a new feature, and one for a known bug I learned a bit more about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for creating DNS records for &lt;code&gt;user.starchart.com&lt;/code&gt;: This is a new feature I filed an issue for. Amazon Cognito, an auth service, requires the parent domain to have an A record, in order to use the subdomain as custom domain for it's managed login. So to use &lt;code&gt;project1-auth.user.starchart.com&lt;/code&gt;, &lt;code&gt;user.starchart.com&lt;/code&gt; must have an A record. If we want to support this use case we'll need to look into this.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/issues/846" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Support creating records for `user.starchart.com`
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#846&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/issues/846" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 24, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;To use a custom domain for Amazon Cognito's managed login, the parent domain must have an A record. For example, to use &lt;code&gt;myproject-auth.user.starchart.com&lt;/code&gt;, an A record must exist for &lt;code&gt;user.starchart.com&lt;/code&gt;. See &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html#cognito-user-pools-add-custom-domain-adding" rel="nofollow noopener noreferrer"&gt;Amazon Cognito: Using your own domain for managed login&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since this is not supported, it's currently not possible to use a custom domain generated with Starchart for Amazon Cognito. Is this something we can look into?&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/issues/846" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;React hydration errors: We've known for a minute that sometimes the CSS will fail to load and I discovered this is because of a series of React hydration errors. Still not sure what causes this so we'll have to investigate.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/issues/845" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        React hydration errors
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#845&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/issues/845" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 24, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Ran into these errors while using the website. They persisted as I navigated between pages. A hard reload (Ctrl + R) made them go away.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://react.dev/errors/418?invariant=418" rel="nofollow noopener noreferrer"&gt;https://react.dev/errors/418?invariant=418&lt;/a&gt;
&lt;a href="https://react.dev/errors/423?invariant=423" rel="nofollow noopener noreferrer"&gt;https://react.dev/errors/423?invariant=423&lt;/a&gt;
&lt;a href="https://react.dev/errors/425?invariant=425" rel="nofollow noopener noreferrer"&gt;https://react.dev/errors/425?invariant=425&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/user-attachments/assets/45bba844-fab4-45f9-9a18-1c4e54607213"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2F45bba844-fab4-45f9-9a18-1c4e54607213" alt="Image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/user-attachments/assets/cb2a6239-0b57-4787-92a7-d20ffc63323b"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2Fcb2a6239-0b57-4787-92a7-d20ffc63323b" alt="Image"&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/issues/845" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Other stuff
&lt;/h2&gt;

&lt;p&gt;I also want to try and contribute to &lt;a href="https://github.com/tarasglek/chatcraft.org" rel="noopener noreferrer"&gt;chatcraft.org&lt;/a&gt;, which some other members of my team have been working on. I found this issue which seems like a good place to start:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/835" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Refactor Code To Use `useChat()` Hook
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#835&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/mulla028" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F138519917%3Fv%3D4" alt="mulla028 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/mulla028" rel="noopener noreferrer"&gt;mulla028&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/835" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 20, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Description&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Since @humphd landed #822, introduced &lt;code&gt;ChatProvider&lt;/code&gt; &amp;amp; &lt;code&gt;useChat()&lt;/code&gt; hook. We need to refactor code to stop passing &lt;code&gt;chat&lt;/code&gt; on &lt;code&gt;props&lt;/code&gt; in components and utilize &lt;code&gt;useChat()&lt;/code&gt; hook wherever it's possible .&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/835" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Trying to Upgrade from Classic Remix Compiler to Remix Vite</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Fri, 21 Feb 2025 03:46:37 +0000</pubDate>
      <link>https://forem.com/uday-rana/trying-to-upgrade-from-classic-remix-compiler-to-remix-vite-4big</link>
      <guid>https://forem.com/uday-rana/trying-to-upgrade-from-classic-remix-compiler-to-remix-vite-4big</guid>
      <description>&lt;p&gt;I've been trying to upgrade our project &lt;a href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;Starchart&lt;/a&gt; from the Classic Remix Compiler to &lt;a href="https://remix.run/docs/en/main/guides/vite" rel="noopener noreferrer"&gt;Remix Vite&lt;/a&gt;. We recently &lt;a href="https://github.com/DevelopingSpace/starchart/pull/833" rel="noopener noreferrer"&gt;upgraded from Remix v1 to v2&lt;/a&gt; and that went pretty smoothly, but this jump is proving pretty tricky. I've run into a number of challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switching from &lt;code&gt;remix watch&lt;/code&gt; to &lt;code&gt;remix dev&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;When we upgraded to Remix v2 we overlooked switching from &lt;code&gt;remix watch&lt;/code&gt; to &lt;code&gt;remix dev&lt;/code&gt;. I had to work on that first before I could begin upgrading to Remix Vite.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/842" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Upgrade `remix watch` to `remix dev`
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#842&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/842" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 20, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;This is an intermediate step in upgrading to Remix Vite.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Changes&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Upgrade &lt;code&gt;remix watch&lt;/code&gt; to &lt;code&gt;remix dev&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;We were supposed to do this when upgrading to v2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;tsx&lt;/code&gt; to run &lt;code&gt;server.ts&lt;/code&gt; and watch for changes instead of building it first with &lt;code&gt;esbuild&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Remix examples use a .js file for the server so I went to the Remix Discord server and they recommended this method. However, this is slower than building the server.&lt;/li&gt;
&lt;li&gt;We no longer need &lt;code&gt;predev&lt;/code&gt;, &lt;code&gt;dev:build&lt;/code&gt;, &lt;code&gt;delay&lt;/code&gt;, &lt;code&gt;dev:remix&lt;/code&gt;, &lt;code&gt;dev:server:delay&lt;/code&gt;, &lt;code&gt;dev:server&lt;/code&gt; scripts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Remove &lt;code&gt;purgeRequireCache&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;According to the video walkthrough linked below this is no longer required.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Remove &lt;code&gt;--require ./node_modules/dotenv/config&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;According to the video walkthrough linked below, this is no longer required because Remix automatically loads &lt;code&gt;.env&lt;/code&gt; files.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;ts-node&lt;/code&gt; with &lt;code&gt;tsx&lt;/code&gt; in &lt;code&gt;prisma.seed&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;We already had &lt;code&gt;ts-node&lt;/code&gt; to run TypeScript files, but Remix recommends &lt;code&gt;tsx&lt;/code&gt; and there's no reason to keep both&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;References&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://remix.run/docs/en/main/start/v2#custom-app-server" rel="nofollow noopener noreferrer"&gt;Upgrading to v2: &lt;code&gt;remix dev&lt;/code&gt;: Custom app server&lt;/a&gt;
&lt;a href="https://remix.run/docs/en/main/other-api/dev#with-custom-app-server" rel="nofollow noopener noreferrer"&gt;@remix-run/dev CLI: &lt;code&gt;remix dev&lt;/code&gt;: With custom app server&lt;/a&gt;
&lt;a href="https://www.youtube.com/watch?v=6jTL8GGbIuc" rel="nofollow noopener noreferrer"&gt;Migrating your project to v2_dev 🚚&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/842" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Custom server built with TypeScript
&lt;/h2&gt;

&lt;p&gt;We're using a custom server written in TypeScript, but all of the examples in the documentation for custom servers are written in JavaScript. There's a footnote that mentions using &lt;code&gt;tsx&lt;/code&gt; or &lt;code&gt;tsm&lt;/code&gt; which I only saw after I'd already switched over to &lt;code&gt;tsx&lt;/code&gt; after looking through Remix's Discord server.&lt;/p&gt;

&lt;p&gt;I had to add &lt;a href="https://vite.dev/guide/api-javascript.html#vitedevserver" rel="noopener noreferrer"&gt;ViteDevServer&lt;/a&gt; to our custom server, but the type definitions for &lt;code&gt;ViteDevServer&lt;/code&gt; are incompatible with Remix. &lt;code&gt;ViteDevServer.ssrLoadmodule&lt;/code&gt; returns &lt;code&gt;Record&amp;lt;string, any&amp;gt;&lt;/code&gt; while &lt;code&gt;createRequestHandler({build})&lt;/code&gt; expects an argument of type &lt;code&gt;ServerBuild&lt;/code&gt;, so I've had to do some weird assertion stuff.&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;createRequestHandler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;viteDevServer&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;viteDevServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ssrLoadModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;virtual:remix/server-build&lt;/span&gt;&lt;span class="dl"&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;mod&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ServerBuild&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;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;mod&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./build/server/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// This import's been giving me some trouble too&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ServerBuild&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;getLoadContext&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;h2&gt;
  
  
  Dynamic import problem
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./build/server/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The dynamic import above is where the server imports all of the server-side code after it's been built. Because of this, the linter and type check are failing in CI, since the module being imported hasn't been built when they're run. I haven't had time to think about the fix - maybe just add an ignore comment - but I feel like there has to be a better solution.&lt;/p&gt;
&lt;h2&gt;
  
  
  CommonJS
&lt;/h2&gt;

&lt;p&gt;We're also compiling our custom server to CommonJS which there aren't any examples for in the Remix docs. All of the examples for Remix Vite use top-level await, which isn't allowed when compiling to CommonJS so I've had to wrap the whole thing in an IIFE. Maybe switching to ES modules would be a better approach?&lt;/p&gt;

&lt;p&gt;There was also this package &lt;code&gt;@emotion/cache&lt;/code&gt; that wouldn't import properly until I used a &lt;a href="https://github.com/cyco130/vite-plugin-cjs-interop" rel="noopener noreferrer"&gt;Vite plugin for CommonJS/ES modules interoperability&lt;/a&gt;.&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;// vite.config.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;vitePlugin&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;remix&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@remix-run/dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;tsconfigPaths&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite-tsconfig-paths&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cjsInterop&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite-plugin-cjs-interop&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This plugin&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITEST&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nf"&gt;remix&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;ignoredRouteFiles&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;**/.*&lt;/span&gt;&lt;span class="dl"&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;**/*.css&lt;/span&gt;&lt;span class="dl"&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;**/*.test.{js,jsx,ts,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;serverModuleFormat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;tsconfigPaths&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="c1"&gt;// https://remix.run/docs/en/main/guides/vite#esm--cjs&lt;/span&gt;
    &lt;span class="nf"&gt;cjsInterop&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;dependencies&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;@emotion/cache&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="na"&gt;optimizeDeps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;include&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;@emotion/cache&lt;/span&gt;&lt;span class="dl"&gt;'&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;h2&gt;
  
  
  Vitest
&lt;/h2&gt;

&lt;p&gt;Also our project is currently on Vitest 0.34 which at one point was causing type errors with Vite 6. I upgraded Vitest to v3 on my branch and fixed the breaking changes and as far as I can tell it's working fine. I just had to switch from &lt;code&gt;watchExclude&lt;/code&gt; to &lt;code&gt;server.watch.ignored&lt;/code&gt;:&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;// vitest.config.ts&lt;/span&gt;

&lt;span class="c1"&gt;// Before&lt;/span&gt;

&lt;span class="c1"&gt;/// &amp;lt;reference types="vitest" /&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;reference types="vite/client" /&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;tsconfigPaths&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite-tsconfig-paths&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;tsconfigPaths&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;setupFiles&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;./test/unit/setup-test-env.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;include&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;./test/unit/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;watchExclude&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;.*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/node_modules&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/.*&lt;/span&gt;&lt;span class="dl"&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;.*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/build&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/.*&lt;/span&gt;&lt;span class="dl"&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;.*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/docker&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/volumes&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/.*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;istanbul&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;tsconfigPaths&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite-tsconfig-paths&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;tsconfigPaths&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;setupFiles&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;./test/unit/setup-test-env.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;include&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;./test/unit/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;istanbul&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;ignored&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;.*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/node_modules&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/.*&lt;/span&gt;&lt;span class="dl"&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;.*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/build&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/.*&lt;/span&gt;&lt;span class="dl"&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;.*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/docker&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/volumes&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/.*&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Why bother?
&lt;/h2&gt;

&lt;p&gt;We're considering migrating to React Router v7 and this is an intermediate step. From what I can tell the jump from Remix Vite to React Router v7 should be simpler than the jump from Classic Remix Compiler to React Vite.&lt;/p&gt;

&lt;p&gt;I'm also a fan of  how much cleaner our npm scripts are (or will be, if I can get this to work).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"run-s build:*"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:remix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"remix build"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbuild --platform=node --format=cjs ./server.ts --outdir=build --bundle"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"predev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run build:server"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env NODE_ENV=development SECRETS_OVERRIDE=1 run-p dev:remix dev:server:delay"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run build:server -- --watch"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"delay"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node -e &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;setTimeout(() =&amp;gt; process.exit(0), 3000)&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:remix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"remix watch"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:server:delay"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"run-s delay dev:server"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node --inspect --require ./node_modules/dotenv/config ./build/server.js"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// After&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env SECRETS_OVERRIDE=1 tsx --inspect ./server.ts"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"remix vite:build"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env SECRETS_OVERRIDE=1 NODE_ENV=production node ./build/server/index.js"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As of now, the &lt;code&gt;dev&lt;/code&gt; script and hot module reloading work, the &lt;code&gt;build&lt;/code&gt; script works, and the app starts, so all hope is not lost.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Upgrade Classic Remix Compiler to Remix Vite
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#843&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 20, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;WIP&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;References&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://remix.run/docs/en/main/guides/vite#migrating" rel="nofollow noopener noreferrer"&gt;Remix Vite: Migrating&lt;/a&gt;
&lt;a href="https://www.youtube.com/watch?v=jmNuEEtwkD4" rel="nofollow noopener noreferrer"&gt;How to Fix CJS/ESM Bugs in Remix&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/843" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h3&gt;
  
  
  Other stuff this week
&lt;/h3&gt;

&lt;p&gt;Other stuff I worked on this week included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improving our contributing documentation&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/836" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Rework CONTRIBUTING.md
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#836&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/836" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 14, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Changes&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Add unit testing instructions&lt;/li&gt;
&lt;li&gt;Add end-to-end testing instructions&lt;/li&gt;
&lt;li&gt;Add contributing workflow section&lt;/li&gt;
&lt;li&gt;Add resources section&lt;/li&gt;
&lt;li&gt;Add separate section with link to wiki to make it more prominent and easier to find&lt;/li&gt;
&lt;li&gt;Split setup commands into separate codeblocks for easy copy pasting&lt;/li&gt;
&lt;li&gt;Add more headings and reword some sections for clarity&lt;/li&gt;
&lt;li&gt;Move testing section directly underneath setup section&lt;/li&gt;
&lt;li&gt;Remove npm prerequisite listing since it comes with Node&lt;/li&gt;
&lt;li&gt;Remove table of contents since GitHub has one baked-in&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/836" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Cleaning up our ignore files (&lt;code&gt;.prettierignore&lt;/code&gt;, &lt;code&gt;.dockerignore&lt;/code&gt;, &lt;code&gt;.gitignore&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/835" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Clean up ignore files
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#835&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/835" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 14, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Changes&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Sort alphabetically&lt;/li&gt;
&lt;li&gt;Remove entries that don't exist (like &lt;code&gt;/e2e&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Add new entries&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/835" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Improving type handling for DNS Record types&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/837" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Improve DNS record type handling
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#837&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/837" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 15, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Follow-up on #830.&lt;/p&gt;
&lt;p&gt;In #830, there was discussion on using a function to map &lt;code&gt;type&lt;/code&gt; to &lt;code&gt;RRType&lt;/code&gt; instead of using &lt;code&gt;type as RRType&lt;/code&gt;: &lt;a href="https://github.com/DevelopingSpace/starchart/pull/830#pullrequestreview-2613283520" rel="noopener noreferrer"&gt;https://github.com/DevelopingSpace/starchart/pull/830#pullrequestreview-2613283520&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Earlier in the code, we're already asserting &lt;code&gt;type as DnsRecordType&lt;/code&gt;, which is a subset of &lt;code&gt;RRType&lt;/code&gt;. I think it makes sense to be consistent and use &lt;code&gt;type as DnsRecordType&lt;/code&gt; here too.&lt;/p&gt;
&lt;p&gt;Also in services/reconciler/route53-client.server.ts &amp;gt; getDnsRecordSetPage(), we can set the type of the &lt;code&gt;type&lt;/code&gt; parameter to RRType so we don't need to map it later.&lt;/p&gt;
&lt;p&gt;Unrelated changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simplified the logic for handling multi-value records to blacklist types that disallow them (there are only two) instead of whitelisting types that allow them, of which new ones have been added to Route53.&lt;/li&gt;
&lt;li&gt;Cleaned up imports in services/reconciler/route53-client.server.ts&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/837" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Adding ESLint 9 back after we removed it a while ago, and configuring it to work together with oxlint&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/834" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add ESLint 9 to support oxlint
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#834&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/834" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 13, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Fixes #803&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Changes&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Added ESLint 9, which is to be run after oxlint as a fallback for linting rules that aren't covered by oxlint. Rules that oxlint does cover won't be linted again by ESLint. This is the approach recommended by oxc:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We recommend running oxlint before ESLint in your lint-staged or CI setup for a quicker feedback loop, considering it only takes a few seconds to run on large codebases.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;I created the config file by grabbing the &lt;a href="https://github.com/remix-run/remix/blob/main/templates/remix/.eslintrc.cjs" rel="noopener noreferrer"&gt;ESLint 8 flat config template recommended by Remix&lt;/a&gt; and using &lt;a href="https://www.npmjs.com/package/@eslint/migrate-config" rel="nofollow noopener noreferrer"&gt;ESLint's config migrator&lt;/a&gt; on it. I then tweaked it from there.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added two oxc plugins not enabled by default: &lt;strong&gt;jsx-a11y&lt;/strong&gt; and &lt;strong&gt;import&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;These plugins don't implement all of the linting rules of their ESLint equivalents, so we need to keep the ESLint plugins too. See &lt;a href="https://github.com/cockpit-project/cockpit/issues/20279" rel="noopener noreferrer"&gt;https://github.com/cockpit-project/cockpit/issues/20279&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Removed some settings from .oxlintrc.json that didn't do anything or were just re-defining the defaults.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fixed lint errors detected after ESLint was added.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/834" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Upgrading from Remix v1 to v2</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Thu, 13 Feb 2025 15:40:30 +0000</pubDate>
      <link>https://forem.com/uday-rana/upgrading-from-remix-v1-to-v2-3ka2</link>
      <guid>https://forem.com/uday-rana/upgrading-from-remix-v1-to-v2-3ka2</guid>
      <description>&lt;p&gt;Last night I worked on upgrading our project &lt;a href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;Starchart&lt;/a&gt; from Remix v1 to v2.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/833" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Update Remix to v2
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#833&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/833" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 13, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Fixes #808&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Changes&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Switch from &lt;code&gt;ThrownResponse&lt;/code&gt; to &lt;code&gt;ErrorResponse&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Switch from &lt;code&gt;@remix-run/node&lt;/code&gt;'s &lt;code&gt;Response&lt;/code&gt; to native &lt;code&gt;Response&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;Blob&lt;/code&gt; to send the body as part of &lt;code&gt;Response&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Switch from &lt;code&gt;LoaderArgs&lt;/code&gt; to &lt;code&gt;LoaderFunctionArgs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Switch from &lt;code&gt;ActionArgs&lt;/code&gt; to &lt;code&gt;ActionFunctionArgs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Switch from &lt;code&gt;V2_MetaFunction&lt;/code&gt; to &lt;code&gt;MetaFunction&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Switch from &lt;code&gt;useActionData();&lt;/code&gt; to &lt;code&gt;useActionData&amp;lt;typeof action&amp;gt;();&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;This is the method used &lt;a href="https://remix.run/docs/en/1.19.3/hooks/use-action-data#useactiondata" rel="nofollow noopener noreferrer"&gt;in the docs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Assert type of &lt;code&gt;route.data&lt;/code&gt; as &lt;code&gt;Record&amp;lt;string, unknown&amp;gt; | undefined&lt;/code&gt; in &lt;code&gt;useMatchesData()&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;This is the method used in &lt;a href="https://github.com/remix-run/examples/tree/main/sharing-loader-data" rel="noopener noreferrer"&gt;this example&lt;/a&gt; which is &lt;a href="https://remix.run/docs/en/1.19.3/hooks/use-matches" rel="nofollow noopener noreferrer"&gt;linked to in the docs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/833" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;It was mostly pretty straightforward, thanks to most &lt;a href="https://remix.run/docs/en/1.19.3/pages/api-development-strategy#goals" rel="noopener noreferrer"&gt;future flags&lt;/a&gt; being already enabled, which meant many breaking changes had already been adopted.&lt;/p&gt;

&lt;p&gt;I followed a "2-minute walkthrough" linked in the &lt;a href="https://remix.run/docs/en/main/start/v2" rel="noopener noreferrer"&gt;upgrade documentation&lt;/a&gt;, which led to me trying to upgrade the whole thing at once instead of incrementally adopting the remaining feature flags. That aside the walkthrough was actually pretty helpful.&lt;/p&gt;

&lt;p&gt;The upgrade was pretty standard stuff - changing some variable names and such - but there were a couple things took me a minute.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Adding &lt;code&gt;&amp;lt;typeof action&amp;gt;&lt;/code&gt; to &lt;code&gt;useActionData()&lt;/code&gt; to make it &lt;code&gt;useActionData&amp;lt;typeof action&amp;gt;()&lt;/code&gt;: I guess this wasn't a requirement in v1 even though &lt;a href="https://remix.run/docs/en/main/hooks/use-action-data" rel="noopener noreferrer"&gt;the docs used &lt;code&gt;&amp;lt;typeof action&amp;gt;&lt;/code&gt;&lt;/a&gt;, so upgrading led to type-check errors. I took a quick look at the docs and added that bit there.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Type-casting &lt;code&gt;useMatches()&lt;/code&gt;: The type-cast in the code below (&lt;code&gt;as&lt;/code&gt;) wasn't in place when we were using v1 and upgrading led to type-check errors. I looked at &lt;a href="https://github.com/remix-run/examples/tree/main/sharing-loader-data" rel="noopener noreferrer"&gt;an example from the docs&lt;/a&gt; for useMatches() and saw they used type-casting so I added it here too, and it fixed the type errors.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;matchingRoutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMatches&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;matchingRoutes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;route&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="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;matchingRoutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// This bit here&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;ul&gt;
&lt;li&gt;Mobile Safari browser &lt;code&gt;ReadableStream&lt;/code&gt; bug: This one took me a while and I wouldn't have figured it out without AI. One of the breaking changes when moving to v2 required switching from &lt;code&gt;@remix-run/node&lt;/code&gt;'s Response to the native Response. To do this I had to convert the &lt;code&gt;body&lt;/code&gt; object passed to the Response to a &lt;code&gt;ReadableStream&lt;/code&gt;. According to the Remix docs the normal way of doing this is using &lt;code&gt;PassThrough&lt;/code&gt; and &lt;code&gt;createReadableStreamFromReadable()&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PassThrough&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createReadableStreamFromReadable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&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="nx"&gt;responseHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;responseStatusCode&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;So when I had to update this section of code, I figured I should use &lt;code&gt;PassThrough&lt;/code&gt; too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unable to get certificate part&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&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;Content-Type&lt;/span&gt;&lt;span class="dl"&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;application/x-pem-file&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unable to get certificate part&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&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;readable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PassThrough&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;readable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&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;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createReadableStreamFromReadable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;readable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&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;Content-Type&lt;/span&gt;&lt;span class="dl"&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;application/x-pem-file&lt;/span&gt;&lt;span class="dl"&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;Content-Disposition&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`attachment; filename=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filename&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="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;But on Mobile Safari, this doesn't work. Something to do with how Safari implements ReadableStream. I saw the implementation tests broke and was able to figure out that this was the change that broke them, since it was the Download test that was failing and this was the only change to the download logic. But I only figured out the actual reason thanks to AI.&lt;/p&gt;

&lt;p&gt;I fixed this by switching to a Blob, which has better compatibility with Mobile Safari.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// After After&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unable to get certificate part&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&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;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/x-pem-file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&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;Content-Type&lt;/span&gt;&lt;span class="dl"&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;application/x-pem-file&lt;/span&gt;&lt;span class="dl"&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;Content-Disposition&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`attachment; filename=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filename&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="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;Interesting bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coming Up Next
&lt;/h2&gt;

&lt;p&gt;Next I want to try and migrate from the classic Remix compiler to &lt;a href="https://remix.run/docs/en/main/guides/vite" rel="noopener noreferrer"&gt;Remix Vite&lt;/a&gt; and then to &lt;a href="https://reactrouter.com/home" rel="noopener noreferrer"&gt;React Router v7&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rust? Never Heard of It. Anyway, Here’s My PR.</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Thu, 06 Feb 2025 03:47:26 +0000</pubDate>
      <link>https://forem.com/uday-rana/rust-never-heard-of-it-anyway-heres-my-pr-egi</link>
      <guid>https://forem.com/uday-rana/rust-never-heard-of-it-anyway-heres-my-pr-egi</guid>
      <description>&lt;p&gt;Last week I signed up for an issue in Hurl, an HTTP request client and testing tool written in Rust.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3637" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        --cookie-jar FILE doesn't work if intermediate directories don't exist
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#3637&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jcamiel" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F16323814%3Fv%3D4" alt="jcamiel avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jcamiel" rel="noopener noreferrer"&gt;jcamiel&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3637" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 24, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;When exporting cookies from a run to &lt;code&gt;SOME_FILE&lt;/code&gt; export is failing if &lt;code&gt;SOME_FILE&lt;/code&gt; has non-existing directory:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell js-code-highlight"&gt;
&lt;pre&gt;$ &lt;span class="pl-c1"&gt;echo&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;HEAD https://hurl.dev&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; hurl --cookie-jar /tmp/a/b/c/out.txt
error: Issue writing to /tmp/a/b/c/out.txt: Os { code: 2, kind: NotFound, message: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;No such file or directory&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; }&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;--cookie-jar&lt;/code&gt; should works like &lt;code&gt;--curll&lt;/code&gt; which create intermediate directories:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell js-code-highlight"&gt;
&lt;pre&gt;$ &lt;span class="pl-c1"&gt;echo&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;HEAD https://hurl.dev&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; hurl --curl /tmp/a/b/c/out.txt&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Note: we could try while fixing this bug to mutualize the code that create a file and it's indermediate directories:&lt;/p&gt;
&lt;div class="highlight highlight-source-rust js-code-highlight"&gt;
&lt;pre&gt; &lt;span class="pl-c"&gt;// We ensure that parent folder is created.&lt;/span&gt;
    &lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-v"&gt;Some&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;parent&lt;span class="pl-kos"&gt;)&lt;/span&gt; = filename&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;parent&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-k"&gt;match&lt;/span&gt; std&lt;span class="pl-kos"&gt;::&lt;/span&gt;fs&lt;span class="pl-kos"&gt;::&lt;/span&gt;&lt;span class="pl-en"&gt;create_dir_all&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;parent&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
            &lt;span class="pl-v"&gt;Ok&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;_&lt;span class="pl-kos"&gt;)&lt;/span&gt; =&amp;gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;
            &lt;span class="pl-v"&gt;Err&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;err&lt;span class="pl-kos"&gt;)&lt;/span&gt; =&amp;gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
                &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-en"&gt;Err&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;ReportError&lt;/span&gt;&lt;span class="pl-kos"&gt;::&lt;/span&gt;&lt;span class="pl-en"&gt;from_error&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
                    err&lt;span class="pl-kos"&gt;,&lt;/span&gt;
                    filename&lt;span class="pl-kos"&gt;,&lt;/span&gt;
                    &lt;span class="pl-s"&gt;"Issue writing TAP report"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
                &lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
            &lt;span class="pl-kos"&gt;}&lt;/span&gt;
        &lt;span class="pl-kos"&gt;}&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;
    &lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-k"&gt;mut&lt;/span&gt; file = &lt;span class="pl-k"&gt;match&lt;/span&gt; &lt;span class="pl-smi"&gt;File&lt;/span&gt;&lt;span class="pl-kos"&gt;::&lt;/span&gt;&lt;span class="pl-en"&gt;create&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;filename&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-v"&gt;Ok&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;f&lt;span class="pl-kos"&gt;)&lt;/span&gt; =&amp;gt; f&lt;span class="pl-kos"&gt;,&lt;/span&gt;
        &lt;span class="pl-v"&gt;Err&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;e&lt;span class="pl-kos"&gt;)&lt;/span&gt; =&amp;gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
            &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-en"&gt;Err&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;ReportError&lt;/span&gt;&lt;span class="pl-kos"&gt;::&lt;/span&gt;&lt;span class="pl-en"&gt;from_error&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
                e&lt;span class="pl-kos"&gt;,&lt;/span&gt;
                filename&lt;span class="pl-kos"&gt;,&lt;/span&gt;
                &lt;span class="pl-s"&gt;"Issue writing TAP report"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
            &lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
        &lt;span class="pl-kos"&gt;}&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Orange-OpenSource/hurl/issues/3637" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I needed to fix a command that accepted a file path so that it would create the parent directories in the path if they didn't exist.&lt;/p&gt;

&lt;p&gt;My knowledge of Rust is rudimentary at best - if you asked me a week ago I would've told you it was nonexistent. When I started working on this my immediate thought process was to go and "learn Rust" - as in go read &lt;a href="https://doc.rust-lang.org/book/" rel="noopener noreferrer"&gt;the Rust book&lt;/a&gt;. I was in the middle of reading what an integer was when I realized it probably wasn't the best use of my time.&lt;/p&gt;

&lt;p&gt;Thinking back to my previous experience working in unfamiliar languages and with unknown technologies, I figured I probably don't necessarily need to "know Rust" to be able to contribute. I worked with Go a little bit last year without needing to go read the Go documentation, so I figured I might as well do what I did last time and just jump in.&lt;/p&gt;

&lt;p&gt;Once I started actually reading the code, I was able to leverage fundamental programming concepts - I could look at the code and understand I was looking at a function, with type annotations for return types. I could understand I was looking at error handling logic, even though the syntax was quite different from what I'm used to in JavaScript-land, where I usually live.&lt;/p&gt;

&lt;p&gt;Even though my first reaction was "Why did I sign up for this?", with that approach, the linter, the unit tests, and some pointers from one of the maintainers, I was able to get the job done.&lt;/p&gt;

&lt;p&gt;According to the issue, the logic for this already existed elsewhere in the source code, so I just had to find it and add it to the function that handled the command. Here's the snippet I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// We ensure that parent folder is created.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="nf"&gt;.parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create_dir_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CliError&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"Issue writing to {}: {err:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="nf"&gt;.display&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;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;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3688" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Create parent folders if missing when using --cookie-jar FILE
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#3688&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3688" rel="noopener noreferrer"&gt;&lt;time&gt;Feb 03, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Fixes #3637&lt;/p&gt;
&lt;p&gt;Please let me know if there's anything I could improve. Thanks.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Orange-OpenSource/hurl/pull/3688" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;In addition to the fix, the maintainer also asked me to do some refactoring, by extracting the parent directory creation logic into a util function and replacing the existing logic with that function throughout the source code. They helped me out by providing some snippets of how they'd prefer it to be done, and by this point I was a little bit more comfortable reading and writing Rust, so it wasn't too bad.&lt;/p&gt;

&lt;p&gt;Here's the same logic but as a function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create parent directories, if missing, given a filepath ending with a file name&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;create_dir_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="nf"&gt;.parent&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="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create_dir_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&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;blockquote&gt;
&lt;p&gt;You might notice this function is calling a standard library function with the same name. That threw me off at first - why was I writing a function when there already is one that does the same thing? The difference is that the standard library function requires a directory path as the argument and doesn't work when it ends in a file name, while this function wraps around it and strips the file name before calling it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With that in place, my changes were accepted. Would I feel confident putting Rust on my resume? Probably not (yet). But it was fun to explore nevertheless.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>My Plans In Open Source This Week</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Sun, 02 Feb 2025 16:20:18 +0000</pubDate>
      <link>https://forem.com/udayr/my-plans-in-open-source-this-week-11of</link>
      <guid>https://forem.com/udayr/my-plans-in-open-source-this-week-11of</guid>
      <description>&lt;p&gt;This is a report on what I plan to work on this week in open source. I signed up for work on two issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hurl: &lt;code&gt;--cookie-jar FILE&lt;/code&gt; doesn't work if intermediate directories don't exist
&lt;/h2&gt;

&lt;p&gt;The first is an issue in &lt;a href="https://github.com/Orange-OpenSource/hurl" rel="noopener noreferrer"&gt;Hurl&lt;/a&gt;, an HTTP request/response client and assertion tool. &lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3637" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        --cookie-jar FILE doesn't work if intermediate directories don't exist
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#3637&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jcamiel" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F16323814%3Fv%3D4" alt="jcamiel avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jcamiel" rel="noopener noreferrer"&gt;jcamiel&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3637" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 24, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;When exporting cookies from a run to &lt;code&gt;SOME_FILE&lt;/code&gt; export is failing if &lt;code&gt;SOME_FILE&lt;/code&gt; has non-existing directory:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell js-code-highlight"&gt;
&lt;pre&gt;$ &lt;span class="pl-c1"&gt;echo&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;HEAD https://hurl.dev&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; hurl --cookie-jar /tmp/a/b/c/out.txt
error: Issue writing to /tmp/a/b/c/out.txt: Os { code: 2, kind: NotFound, message: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;No such file or directory&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; }&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;--cookie-jar&lt;/code&gt; should works like &lt;code&gt;--curll&lt;/code&gt; which create intermediate directories:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell js-code-highlight"&gt;
&lt;pre&gt;$ &lt;span class="pl-c1"&gt;echo&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;HEAD https://hurl.dev&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; hurl --curl /tmp/a/b/c/out.txt&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Note: we could try while fixing this bug to mutualize the code that create a file and it's indermediate directories:&lt;/p&gt;
&lt;div class="highlight highlight-source-rust js-code-highlight"&gt;
&lt;pre&gt; &lt;span class="pl-c"&gt;// We ensure that parent folder is created.&lt;/span&gt;
    &lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-v"&gt;Some&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;parent&lt;span class="pl-kos"&gt;)&lt;/span&gt; = filename&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;parent&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-k"&gt;match&lt;/span&gt; std&lt;span class="pl-kos"&gt;::&lt;/span&gt;fs&lt;span class="pl-kos"&gt;::&lt;/span&gt;&lt;span class="pl-en"&gt;create_dir_all&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;parent&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
            &lt;span class="pl-v"&gt;Ok&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;_&lt;span class="pl-kos"&gt;)&lt;/span&gt; =&amp;gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;
            &lt;span class="pl-v"&gt;Err&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;err&lt;span class="pl-kos"&gt;)&lt;/span&gt; =&amp;gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
                &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-en"&gt;Err&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;ReportError&lt;/span&gt;&lt;span class="pl-kos"&gt;::&lt;/span&gt;&lt;span class="pl-en"&gt;from_error&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
                    err&lt;span class="pl-kos"&gt;,&lt;/span&gt;
                    filename&lt;span class="pl-kos"&gt;,&lt;/span&gt;
                    &lt;span class="pl-s"&gt;"Issue writing TAP report"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
                &lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
            &lt;span class="pl-kos"&gt;}&lt;/span&gt;
        &lt;span class="pl-kos"&gt;}&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;
    &lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-k"&gt;mut&lt;/span&gt; file = &lt;span class="pl-k"&gt;match&lt;/span&gt; &lt;span class="pl-smi"&gt;File&lt;/span&gt;&lt;span class="pl-kos"&gt;::&lt;/span&gt;&lt;span class="pl-en"&gt;create&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;filename&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-v"&gt;Ok&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;f&lt;span class="pl-kos"&gt;)&lt;/span&gt; =&amp;gt; f&lt;span class="pl-kos"&gt;,&lt;/span&gt;
        &lt;span class="pl-v"&gt;Err&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;e&lt;span class="pl-kos"&gt;)&lt;/span&gt; =&amp;gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
            &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-en"&gt;Err&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-smi"&gt;ReportError&lt;/span&gt;&lt;span class="pl-kos"&gt;::&lt;/span&gt;&lt;span class="pl-en"&gt;from_error&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
                e&lt;span class="pl-kos"&gt;,&lt;/span&gt;
                filename&lt;span class="pl-kos"&gt;,&lt;/span&gt;
                &lt;span class="pl-s"&gt;"Issue writing TAP report"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
            &lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
        &lt;span class="pl-kos"&gt;}&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Orange-OpenSource/hurl/issues/3637" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This issue concerns the command &lt;code&gt;--cookie-jar &amp;lt;FILE&amp;gt;&lt;/code&gt;. If the file path specified contains intermediate directories that doesn't exist, it throws an error. We want it to automatically create the intermediate directories.&lt;/p&gt;

&lt;p&gt;Hurl is a tool that I use (and still use) in my own projects. I want to continue doing meaningful work and I thought this would be a good way to get back into the flow of things since I haven't done much open source work since December. This will also be my first time working with Rust, which I'm looking forward to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starchart: Add ability to create and manage MX records
&lt;/h2&gt;

&lt;p&gt;The second issue I signed up for is an issue in &lt;a href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;Starchart&lt;/a&gt;, our in-house tool for creating and managing custom subdomains.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/issues/787" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add ability to create and manage MX records
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#787&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/humphd" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F427398%3Fv%3D4" alt="humphd avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/humphd" rel="noopener noreferrer"&gt;humphd&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/issues/787" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 24, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Currently you can create the following types of DNS records:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A&lt;/li&gt;
&lt;li&gt;AAAA&lt;/li&gt;
&lt;li&gt;CNAME&lt;/li&gt;
&lt;li&gt;TXT&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A request has come in to support also including &lt;a href="https://en.wikipedia.org/wiki/MX_record" rel="nofollow noopener noreferrer"&gt;MX records&lt;/a&gt; for defining names for email hosts.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/issues/787" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;We want to add support for MX records, a type of DNS record for mail servers. I'm not too familiar with how the app manages DNS records so I'll have to do some research. This issue seems rather large in scope, so while I &lt;em&gt;will&lt;/em&gt; be working on the implementation, I don't expect to finish it within the week. My professor also suggested I split it up into smaller issues - writing tests and doing the actual implementation - and let somebody else do the other half.&lt;/p&gt;

&lt;p&gt;I signed up for this because we've been updating dependencies in this project for a couple weeks now to bring it up to date, but haven't had a chance to dive into the actual code, so I thought it'd be nice to finally do just that.&lt;/p&gt;

&lt;p&gt;I did do some other minor stuff like cleaning up &lt;code&gt;.prettierignore&lt;/code&gt;, adding an &lt;code&gt;.nvmrc&lt;/code&gt; file, adding &lt;code&gt;docker compose down&lt;/code&gt; to the contributing docs, and organizing the project structure a little.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/812" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Remove .prettierignore entries that are already in .gitignore
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#812&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/812" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 31, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Fixes #811&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/812" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/809" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add `docker compose down` to contributing docs
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#809&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/809" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 30, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Fixes #771&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/809" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/806" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add .nvmrc
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#806&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/806" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 30, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Fixes #773&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/806" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/810" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Move docs into /docs
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#810&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/810" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 31, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;I think it'd be nice to clean the project root directory up to make it a little easier to navigate. This moves the documentation and images into /docs so they're not mixed in with config files and such.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/810" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/813" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Move mysql and redis bind mounts to /docker/volumes
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#813&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/813" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 31, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;This aims to make the project root directory a bit more organized by moving all bind mounts under a single directory.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/813" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I'll do a progress report on Wednesday with how the issues are going.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Reviving An Outdated Project</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Tue, 21 Jan 2025 21:36:30 +0000</pubDate>
      <link>https://forem.com/uday-rana/reviving-an-outdated-project-3eij</link>
      <guid>https://forem.com/uday-rana/reviving-an-outdated-project-3eij</guid>
      <description>&lt;p&gt;This week, I did some some maintenance work on &lt;a href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;Starchart&lt;/a&gt;. The project hasn't been worked on in a while so we're trying to update it's dependencies.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/DevelopingSpace" rel="noopener noreferrer"&gt;
        DevelopingSpace
      &lt;/a&gt; / &lt;a href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;
        starchart
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A self-serve tool for managing custom domains and certificates
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Starchart &lt;a href="https://github.com/DevelopingSpace/starchartLICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6cd0120cc4c5ac11d28b2c60f76033b52db98dac641de3b2644bb054b449d60c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667" alt="License: MIT"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Starchart makes it easy for the Seneca developer community to create and manage their own custom subdomains and SSL certificates, without cost or having to provide personal information.&lt;/p&gt;
&lt;p&gt;For information about running Starchart, see our &lt;a href="https://github.com/DevelopingSpace/starchartdocs/deployment.md" rel="noopener noreferrer"&gt;deployment guide&lt;/a&gt;. For development information, see our &lt;a href="https://github.com/DevelopingSpace/starchartCONTRIBUTING.md" rel="noopener noreferrer"&gt;contributing guide&lt;/a&gt;. For further technical background, planning, and initial designs, please see the &lt;a href="https://github.com/Seneca-CDOT/starchart/wiki" rel="noopener noreferrer"&gt;wiki&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Introduction&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The internet is evolving, and what used to be hard has become simple. For example, hosting your own website used to require knowledge of server administration, operating systems, networking, etc. Today, many developers host their personal and project websites without ever touching a remote server, opting for (free) cloud services like GitHub Pages, Vercel, Netlify, or AWS.&lt;/p&gt;
&lt;p&gt;The internet's security model is also evolving. For example, browser vendors have embraced HTTPS everywhere. This is good for security, as it enables certificate-based encryption between clients and servers. However, as with…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The plan was to fix the CI workflow, which we found out was broken last week:&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%2Fp1rnw59hly3lxhhzlq18.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%2Fp1rnw59hly3lxhhzlq18.png" alt="Image description" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But before I could work out a fix, one of the previous developers, &lt;a href="https://dev.to/eakam"&gt;Eakam&lt;/a&gt;, solved the issue - turns out it was just because Playwright was outdated.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/772" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Bump playwright to 1.49.1
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#772&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/Eakam1007" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F67077705%3Fv%3D4" alt="Eakam1007 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/Eakam1007" rel="noopener noreferrer"&gt;Eakam1007&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/772" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 18, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Playwright install is failing in CI (E2E Tests). Bumping playwright version should fix that.&lt;/p&gt;
&lt;p&gt;Ref:
&lt;a rel="noopener noreferrer" href="https://github.com/user-attachments/assets/c7099f90-c354-4f41-94d9-4d510e74a779"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2Fc7099f90-c354-4f41-94d9-4d510e74a779" alt="Installation error log"&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/772" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I felt like I should make up for it by finding more stuff to work on and thought updating more dependencies would be a great starting point.&lt;/p&gt;

&lt;p&gt;Since the project hadn't been worked on for 2 years, there were a bunch of security vulnerabilities stemming from outdated packages. I was able to fix most of them with &lt;code&gt;npm audit fix&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There were a couple more fixes that led to breaking changes in &lt;code&gt;@remix-run/eslint-config&lt;/code&gt; and &lt;code&gt;@remix-run/react&lt;/code&gt;, so I bumped those manually. &lt;/p&gt;

&lt;p&gt;One of the updates (I bumped them at the same time so I can't say for sure but my bet is on &lt;code&gt;/react&lt;/code&gt;) led to a type-check error because &lt;code&gt;[@remix-run/react].useNavigation().formData&lt;/code&gt; may now be of the type undefined. I fixed it with optional chaining.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submitting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formData&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;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;dnsRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submitting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formData&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;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;dnsRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The other changes I made had to do with some lint errors that popped up (At this point I realized I had my ESLint extension turned off, but I'm sure these warnings came with the update, since it never happened in CI in the past).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instances of importing the same module multiple times in one file:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getCertificateByUsername&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/models/certificate.server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;deleteCertificateById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/models/certificate.server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isAdmin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/models/user.server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUserByUsername&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/models/user.server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getCertificateByUsername&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;deleteCertificateById&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/models/certificate.server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getUserByUsername&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/models/user.server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Using &lt;code&gt;let&lt;/code&gt; when &lt;code&gt;const&lt;/code&gt; is preferred:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&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;Surprised it didn't catch these before.&lt;/p&gt;

&lt;p&gt;Also, when I turned on the ESLint extension I was a little taken aback because there were ~900 linter errors. Turned out it was because ESLint was linting the output generated by Playwright. So I added &lt;code&gt;/playwright-report&lt;/code&gt; to .eslintignore.&lt;/p&gt;

&lt;p&gt;And that was the sum of my maintenance work for this sprint. Ended up fixing 30+ severe security issues, so not bad.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/775" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Update dependencies
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#775&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/775" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 18, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Should fix a bunch of security vulnerabilities.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Changes&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;[x] Bump dependencies&lt;/li&gt;
&lt;li&gt;[x] Add /playwright-report to .eslintignore&lt;/li&gt;
&lt;li&gt;[x] Fix typecheck and linter errors&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/775" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;I also re-activated Dependabot which bumped vitest a couple minor versions. It'll be nice to not have to manually investigate and patch security vulnerabilities.&lt;/p&gt;

&lt;p&gt;In other news, one of my pull requests to Mattermost was finally merged!&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/mattermost/mattermost/pull/29558" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        [GH-29548] Avoid SELECT * in `tokens_store.go`
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#29558&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/mattermost/mattermost/pull/29558" rel="noopener noreferrer"&gt;&lt;time&gt;Dec 10, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Summary&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;This PR:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Switches SQL queries in &lt;code&gt;token_store.go&lt;/code&gt; to use SQLBuilder&lt;/li&gt;
&lt;li&gt;Explicitly defines columns in SELECT queries to TokenStore.&lt;/li&gt;
&lt;li&gt;Factors out common queries into the constructor.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Ticket Link&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Fixes #29548&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Screenshots&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Release Note&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

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

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mattermost/mattermost/pull/29558" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;It'd been approved a while ago but it took a few weeks to be merged into main.&lt;/p&gt;

&lt;p&gt;In the meantime I've been working on my other PR. I was asked to make some changes and I'm waiting on a re-review.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/mattermost/mattermost/pull/29414" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        [MM-53650] Add disable emoticon rendering setting to webapp
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#29414&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/mattermost/mattermost/pull/29414" rel="noopener noreferrer"&gt;&lt;time&gt;Nov 28, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Summary&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;This pull request adds a user setting to the webapp to toggle rendering emoticons (&lt;code&gt;:D&lt;/code&gt;) as emojis (😄).&lt;/p&gt;
&lt;p&gt;The setting is added as a component in &lt;code&gt;components/user_settings/display/render_emoticons_as_emoji/&lt;/code&gt; which is imported in &lt;code&gt;components/user_settings/display/user_settings_display.tsx&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I've added a &lt;code&gt;renderOnOffLabel()&lt;/code&gt; function to &lt;code&gt;user_settings_display.tsx&lt;/code&gt;, lifted from &lt;code&gt;components/user_settings/advanced/user_settings_advanced.tsx&lt;/code&gt; to help render the new component.&lt;/p&gt;
&lt;p&gt;The setting is stored as a user preference using the &lt;code&gt;savePreferences()&lt;/code&gt; action.&lt;/p&gt;
&lt;p&gt;I've added constants for the preference to &lt;code&gt;utils/constants.tsx&lt;/code&gt; and &lt;code&gt;webapp/channels/src/packages/mattermost-redux/src/constants/preferences.ts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To actually use the setting, I've modified &lt;code&gt;components/post_markdown&lt;/code&gt; to receive it's value as a prop, for which I've used &lt;code&gt;getBool()&lt;/code&gt; and added a default value to the config. &lt;code&gt;post_markdown&lt;/code&gt; passes this value down to &lt;code&gt;Markdown&lt;/code&gt; on the &lt;code&gt;options&lt;/code&gt; object, which then passes it down to &lt;code&gt;utils/text_formatting.tsx&lt;/code&gt;, which finally passes the value to &lt;code&gt;emoticons.tsx&lt;/code&gt; as a newly added parameter. &lt;code&gt;emoticons.tsx&lt;/code&gt; checks whether the value is true and if it is, it transforms the emoticons into emojis.&lt;/p&gt;
&lt;p&gt;I've updated affected tests and created unit tests for the new component. I've also updated the English translation file.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h5 class="heading-element"&gt;QA Test Steps&lt;/h5&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to User Settings.&lt;/li&gt;
&lt;li&gt;Go to the Display category.&lt;/li&gt;
&lt;li&gt;Find the section labelled "Auto-render emoticons as emoji" and click "Edit".&lt;/li&gt;
&lt;li&gt;Toggle the setting and click "Save".&lt;/li&gt;
&lt;li&gt;Emoticon rendering on messages sent by the current user and other users should be toggled client-side with the setting.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Ticket Link&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Fixes (partially) &lt;a href="https://github.com/mattermost/mattermost/issues/26504" rel="noopener noreferrer"&gt;https://github.com/mattermost/mattermost/issues/26504&lt;/a&gt;
Jira &lt;a href="https://mattermost.atlassian.net/browse/MM-53650" rel="nofollow noopener noreferrer"&gt;https://mattermost.atlassian.net/browse/MM-53650&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; the issue and ticket describe adding this feature to the mobile app as well, which this PR does not.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Screenshots&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;before&lt;/th&gt;
&lt;th&gt;after&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer" href="https://github.com/user-attachments/assets/17600204-6446-4206-ab86-a8aea7ed05b3"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2F17600204-6446-4206-ab86-a8aea7ed05b3" alt="image"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer" href="https://github.com/user-attachments/assets/cc7ac7bf-1eb8-47c5-bb93-abce42bc006a"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2Fcc7ac7bf-1eb8-47c5-bb93-abce42bc006a" alt="image"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Release Note&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;pre&gt;&lt;code&gt;Added a new user setting to toggle rendering emoticons (:D) as emojis (😄)
&lt;/code&gt;&lt;/pre&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mattermost/mattermost/pull/29414" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Working on this PR was interesting because when I first submitted it I didn't even entirely understand my changes. Going back into it after a long while away and with the feedback from the reviews helped me look at it from a fresh perspective and understand it better.&lt;/p&gt;

&lt;p&gt;The Mattermost app gets user setting state from both "preferences" and from a "config". I added my setting to both, mimicking one of the existing settings I was advised to reference, but it turned out the "config" is for server-level settings, while this new setting was intended to be a client-side option. The reviews helped me understand where I went wrong, and it actually ended up being a smaller change than I thought necessary.&lt;/p&gt;

&lt;p&gt;Overall I'd say it was a fairly productive week.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>osd700</category>
    </item>
    <item>
      <title>Becoming An Open Source Maintainer</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Tue, 14 Jan 2025 23:17:34 +0000</pubDate>
      <link>https://forem.com/udayrana/becoming-an-open-source-maintainer-2a6a</link>
      <guid>https://forem.com/udayrana/becoming-an-open-source-maintainer-2a6a</guid>
      <description>&lt;p&gt;I've had the opportunity to enrol in &lt;a href="https://syl.senecapolytechnic.ca/syllabi/2025-winter/osd700-nsa-4820/index.html" rel="noopener noreferrer"&gt;OSD700 - Open Source Development Project&lt;/a&gt; at Seneca Polytechnic, where I'll be learning to maintain and ship open source software as part of a team. As a part of the course, I'll be blogging weekly about everything I work on.&lt;/p&gt;

&lt;p&gt;This term, we're going to be maintaining two projects: &lt;a href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;Starchart&lt;/a&gt; and &lt;a href="https://github.com/tarasglek/chatcraft.org" rel="noopener noreferrer"&gt;ChatCraft&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/DevelopingSpace" rel="noopener noreferrer"&gt;
        DevelopingSpace
      &lt;/a&gt; / &lt;a href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;
        starchart
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A self-serve tool for managing custom domains and certificates
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Starchart &lt;a href="https://github.com/DevelopingSpace/starchartLICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6cd0120cc4c5ac11d28b2c60f76033b52db98dac641de3b2644bb054b449d60c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667" alt="License: MIT"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Starchart makes it easy for the Seneca developer community to create and manager their own custom subdomains and SSL certificates, without cost or having to provide personal information.&lt;/p&gt;
&lt;p&gt;For information about running Starchart, see our &lt;a href="https://github.com/DevelopingSpace/starchartDEPLOY.md" rel="noopener noreferrer"&gt;deployment guide&lt;/a&gt;. For development information, see our &lt;a href="https://github.com/DevelopingSpace/starchartCONTRIBUTING.md" rel="noopener noreferrer"&gt;contributing guide&lt;/a&gt;. For further technical background, planning, and initial designs, please see the &lt;a href="https://github.com/Seneca-CDOT/starchart/wiki" rel="noopener noreferrer"&gt;wiki&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Introduction&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The internet is evolving, and what used to be hard has become simple. For example, hosting your own website used to require knowledge of server administration, operating systems, networking, etc. Today, many developers host their personal and project websites without ever touching a remote server, opting for (free) cloud services like GitHub Pages, Vercel, Netlify, or AWS.&lt;/p&gt;
&lt;p&gt;The internet's security model is also evolving. For example, browser vendors have embraced HTTPS everywhere. This is good for security, as it enables certificate-based encryption between clients and servers. However, as with…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/tarasglek" rel="noopener noreferrer"&gt;
        tarasglek
      &lt;/a&gt; / &lt;a href="https://github.com/tarasglek/chatcraft.org" rel="noopener noreferrer"&gt;
        chatcraft.org
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Developer-oriented ChatGPT clone
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;ChatCraft.org&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Welcome to &lt;a href="https://chatcraft.org" rel="nofollow noopener noreferrer"&gt;ChatCraft.org&lt;/a&gt;, your open-source web companion for coding with Large Language Models (LLMs). Designed with developers in mind, ChatCraft transforms the way you interact with GPT models, making it effortless to read, write, debug, and enhance your code.&lt;/p&gt;
&lt;p&gt;Whether you're exploring new designs or learning about the latest technologies, ChatCraft is your go-to platform. With a user interface inspired by GitHub, and editable Markdown everywhere, you'll feel right at home from the get-go.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.orgdocs/chatcraft-example.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftarasglek%2Fchatcraft.orgdocs%2Fchatcraft-example.png" alt="ChatCraft UI Example"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;We think ChatCraft is the best platform for learning, experimenting, and getting creative with code. Here's a few of the reasons why we think you'll agree:&lt;/p&gt;
&lt;p&gt;🛠️ &lt;strong&gt;You're in Control&lt;/strong&gt;: Customize all aspects of a chat. Use your own System Prompts, edit, delete, and retry AI messages with models from competing vendors in the same chat.&lt;/p&gt;
&lt;p&gt;🌍 &lt;strong&gt;Multiple AI Providers&lt;/strong&gt;: ChatCraft supports both OpenAI and OpenRouter, giving you access to a…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I'll talk about my experience setting these up, and what I plan to work on for this sprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the projects
&lt;/h2&gt;

&lt;p&gt;I was able to get both projects up and running fairly easily following the documentation. Starchart is an old project and hasn't been maintained for about two years, so I got warnings for a bunch of out-of-date dependencies, but was still able to get the webapp running.&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%2Fao2q7boxeemglhm1j1fg.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%2Fao2q7boxeemglhm1j1fg.png" alt="Starchart latest commit" width="800" height="104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ChatCraft is much more actively maintained, so I didn't run into any trouble setting it up.&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%2F9jrqrtn21oayls0d59vn.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%2F9jrqrtn21oayls0d59vn.png" alt="ChatCraft latest commit" width="800" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  First Contributions
&lt;/h2&gt;

&lt;p&gt;I submitted some issues / pull requests for both projects - some feature suggestions and some documentation updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starchart
&lt;/h3&gt;

&lt;p&gt;For Starchart, I noticed a few areas for improvement in the docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The contributing docs don't mention &lt;code&gt;docker compose down&lt;/code&gt;, so contributors unfamiliar with Docker Compose might end up leaving the Docker services on their machines.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/issues/771" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add `docker compose down` to contributing docs
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#771&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/issues/771" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 15, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;The contributing docs don't mention &lt;code&gt;docker compose down&lt;/code&gt;, so contributors unfamiliar with Docker Compose might end up leaving the containers on their machines.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/issues/771" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;The section on squashing and merging pull requests has some misleading info saying squashing helps prevent losing the commit history.&lt;/li&gt;
&lt;/ul&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%2Fb9dymyu3c5hckqod2dxm.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%2Fb9dymyu3c5hckqod2dxm.png" alt="Misleading squash merge explanation" width="800" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I think we could write a Makefile to simplify the developer environment setup and teardown.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/issues/770" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Simplify dev environment setup with a Makefile
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#770&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/issues/770" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 15, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;I think we can simplify the dev environment setup using a Makefile so that a single command can run all the necessary scripts:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/DevelopingSpace/starchart/blob/bf23d1c5e84298165463e34cb337f00aeb07f862/CONTRIBUTING.md?plain=1#L37-L63" rel="noopener noreferrer"&gt;https://github.com/DevelopingSpace/starchart/blob/bf23d1c5e84298165463e34cb337f00aeb07f862/CONTRIBUTING.md?plain=1#L37-L63&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/issues/770" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I made a pull request to fix some typos and the section on merging pull requests. Unfortunately, it looks like Starchart's CI workflow is broken, because Playwright fails to install the dependencies it needs to run end-to-end tests. I haven't been able replicate this error on my local machine - I assume it's because of differences between my environment and the GitHub Actions environment. I'll have to look into the CI workflow.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/768" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Fix typos and "Merging to main" section in CONTRIBUTING.md
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#768&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/768" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 09, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Fixes #767.&lt;/p&gt;
&lt;p&gt;Fixed some typos. Also:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/DevelopingSpace/starchart/blob/bf23d1c5e84298165463e34cb337f00aeb07f862/CONTRIBUTING.md?plain=1#L122-L129" rel="noopener noreferrer"&gt;https://github.com/DevelopingSpace/starchart/blob/bf23d1c5e84298165463e34cb337f00aeb07f862/CONTRIBUTING.md?plain=1#L122-L129&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This section says that squashing and merging pull requests helps prevent losing the commit history which is not true. I've streamlined the section to remove that part.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DevelopingSpace/starchart/pull/768" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Until this is resolved I've decided to hold off on making pull requests for the other two issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  ChatCraft
&lt;/h3&gt;

&lt;p&gt;As for ChatCraft, the Getting Started section of it's README had what I understood to be slightly outdated instructions, instructing new users to select an AI provider and to enter an API Key. These are optional steps tucked away in the settings, a fact the instructions failed to mention (which confused me when trying it out the first time). I filed an issue to address this.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/776" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        README "Getting Started" section improvements
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#776&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/776" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 09, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;The Getting Started section of the README talks about choosing an AI provider and entering an API key, but fails to mention where to find these settings and that these steps are optional:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/blob/747d1026e3eee0ca3db829b2f09fe9ded42b83e2/README.md?plain=1#L33-L42" rel="noopener noreferrer"&gt;https://github.com/tarasglek/chatcraft.org/blob/747d1026e3eee0ca3db829b2f09fe9ded42b83e2/README.md?plain=1#L33-L42&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We could either remove those steps for the sake of simplicity (since it is supposed to be "Getting Started"), or label them as optional and mention where users can find those options.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/776" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I also opened an issue for adding a setting which updates the app theme dynamically when the system theme changes, instead of reading the system theme on start and then requiring manual toggling.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/781" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add "Use System Theme" setting
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#781&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/781" rel="noopener noreferrer"&gt;&lt;time&gt;Jan 14, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;I'd like a setting that makes the app theme change dynamically when the system theme changes.&lt;/p&gt;
&lt;p&gt;I think setting &lt;code&gt;useSystemColorMode&lt;/code&gt; to true if the setting is toggled on would work:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/blob/c2f7165a7225492dcd1c1ef18e65272e3f5f59ab/src/theme.ts#L5-L10" rel="noopener noreferrer"&gt;https://github.com/tarasglek/chatcraft.org/blob/c2f7165a7225492dcd1c1ef18e65272e3f5f59ab/src/theme.ts#L5-L10&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Maybe also hide/disable the theme toggle button when this is on?&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/781" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Other Plans For This Sprint
&lt;/h2&gt;

&lt;p&gt;In terms of other stuff for this sprint, I'm still working on one of my pull requests to Mattermost from a while ago - I received a review last week so I have some changes to make:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/mattermost/mattermost/pull/29414" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        [MM-53650] Add disable emoticon rendering setting to webapp
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#29414&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F82779467%3Fv%3D4" alt="uday-rana avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;uday-rana&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/mattermost/mattermost/pull/29414" rel="noopener noreferrer"&gt;&lt;time&gt;Nov 28, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Summary&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;This pull request adds a user setting to the webapp to toggle rendering emoticons (&lt;code&gt;:D&lt;/code&gt;) as emojis (😄).&lt;/p&gt;
&lt;p&gt;The setting is added as a component in &lt;code&gt;components/user_settings/display/render_emoticons_as_emoji/&lt;/code&gt; which is imported in &lt;code&gt;components/user_settings/display/user_settings_display.tsx&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I've added a &lt;code&gt;renderOnOffLabel()&lt;/code&gt; function to &lt;code&gt;user_settings_display.tsx&lt;/code&gt;, lifted from &lt;code&gt;components/user_settings/advanced/user_settings_advanced.tsx&lt;/code&gt; to help render the new component.&lt;/p&gt;
&lt;p&gt;The setting is stored as a user preference using the &lt;code&gt;savePreferences()&lt;/code&gt; action.&lt;/p&gt;
&lt;p&gt;I've added constants for the preference to &lt;code&gt;utils/constants.tsx&lt;/code&gt; and &lt;code&gt;webapp/channels/src/packages/mattermost-redux/src/constants/preferences.ts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To actually use the setting, I've modified &lt;code&gt;components/post_markdown&lt;/code&gt; to receive it's value as a prop, for which I've used &lt;code&gt;getBool()&lt;/code&gt; and added a default value to the config. &lt;code&gt;post_markdown&lt;/code&gt; passes this value down to &lt;code&gt;Markdown&lt;/code&gt; on the &lt;code&gt;options&lt;/code&gt; object, which then passes it down to &lt;code&gt;utils/text_formatting.tsx&lt;/code&gt;, which finally passes the value to &lt;code&gt;emoticons.tsx&lt;/code&gt; as a newly added parameter. &lt;code&gt;emoticons.tsx&lt;/code&gt; checks whether the value is true and if it is, it transforms the emoticons into emojis.&lt;/p&gt;
&lt;p&gt;I've updated affected tests and created unit tests for the new component. I've also updated the English translation file.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h5 class="heading-element"&gt;QA Test Steps&lt;/h5&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to User Settings.&lt;/li&gt;
&lt;li&gt;Go to the Display category.&lt;/li&gt;
&lt;li&gt;Find the section labelled "Auto-render emoticons as emoji" and click "Edit".&lt;/li&gt;
&lt;li&gt;Toggle the setting and click "Save".&lt;/li&gt;
&lt;li&gt;Emoticon rendering on messages sent by the current user and other users should be toggled client-side with the setting.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Ticket Link&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;Fixes (partially) &lt;a href="https://github.com/mattermost/mattermost/issues/26504" rel="noopener noreferrer"&gt;https://github.com/mattermost/mattermost/issues/26504&lt;/a&gt;
Jira &lt;a href="https://mattermost.atlassian.net/browse/MM-53650" rel="nofollow noopener noreferrer"&gt;https://mattermost.atlassian.net/browse/MM-53650&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; the issue and ticket describe adding this feature to the mobile app as well, which this PR does not.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Screenshots&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;before&lt;/th&gt;
&lt;th&gt;after&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer" href="https://github.com/user-attachments/assets/17600204-6446-4206-ab86-a8aea7ed05b3"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2F17600204-6446-4206-ab86-a8aea7ed05b3" alt="image"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer" href="https://github.com/user-attachments/assets/cc7ac7bf-1eb8-47c5-bb93-abce42bc006a"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2Fcc7ac7bf-1eb8-47c5-bb93-abce42bc006a" alt="image"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Release Note&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;pre&gt;&lt;code&gt;Added a new user setting to toggle rendering emoticons (:D) as emojis (😄)
&lt;/code&gt;&lt;/pre&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mattermost/mattermost/pull/29414" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>opensource</category>
      <category>osd700</category>
    </item>
    <item>
      <title>Looking Back On My Work</title>
      <dc:creator>Uday Rana</dc:creator>
      <pubDate>Thu, 12 Dec 2024 05:36:34 +0000</pubDate>
      <link>https://forem.com/udayrana/looking-back-on-my-work-50ad</link>
      <guid>https://forem.com/udayrana/looking-back-on-my-work-50ad</guid>
      <description>&lt;p&gt;In this post I'll be reviewing my progress in open source over the past few weeks.&lt;/p&gt;

&lt;p&gt;Originally, my plan for this past month or so was to work on Mattermost Mobile, where I was going to add a feature to toggle rendering emoticons as emojis. I worked on the same feature in the webapp, so I figured I should have a solid idea of what I needed to do. Quick update on the webapp pull request by the way, my changes were finally reviewed by the contributors. I'll be working on making the requested changes over the next few days.&lt;/p&gt;

&lt;p&gt;Anyway, unfortunately, I ended up being way busier than I could've anticipated and I wasn't able to start on the mobile issue until very recently, where I immediately hit a roadblock in not being able to set up the dev environment due to my operating system, meaning I couldn't do the work I was planning on, and had to change gears fast to still get contributions in. I decided my best option was to look for smaller, but still substantial issues.&lt;/p&gt;

&lt;p&gt;I looked through GitHub for issues labelled "help wanted", and ended up finding a couple more Mattermost issues, along with one for the GitHub CLI:&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 1: Github CLI - Improving output formatting
&lt;/h3&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/cli/cli/issues/10038" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        `gh run view` should list branches in square brackets
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#10038&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/BagToad" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F47394200%3Fv%3D4" alt="BagToad avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/BagToad" rel="noopener noreferrer"&gt;BagToad&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/cli/cli/issues/10038" rel="noopener noreferrer"&gt;&lt;time&gt;Dec 07, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Describe the bug&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;gh run view&lt;/code&gt; lists branches in parenthesis, but I think it should list them in square brackets to align with &lt;a href="https://primer.style/native/cli/components#branches" rel="nofollow noopener noreferrer"&gt;Primer guidelines&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Display branch names in brackets and/or cyan&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Steps to reproduce the behavior&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;gh run view&lt;/code&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Expected vs actual behavior&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;gh run view&lt;/code&gt; prompts should display branches within square brackets.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Logs&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code&gt;❯ gh run view
? Select a workflow run  [Use arrows to move, type to filter]
&amp;gt; - Verifying attestations offline fails, Discussion Triage (trunk) 4h55m1s ago
  - Decoding, Discussion Triage (patch-1) 4h59m32s ago
  ✓ Decoding, PR Automation (patch-1) 4h59m43s ago
  ✓ Issue Automation, Issue Automation (trunk) 5h20m31s ago
  - `gh repo rename myorg/newname` results in `myorg/myorg-newname`, Discussion Triage (trunk) 10h13m50s ago
  - 401 Error at every turn, Discussion Triage (trunk) 10h15m20s ago
  - 401 Error at every turn, Discussion Triage (trunk) 10h15m20s ago
&lt;/code&gt;&lt;/pre&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/cli/cli/issues/10038" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Issue 2: Mattermost - Adding timestamps to pasted image filenames
&lt;/h3&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/mattermost/mattermost/issues/29524" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add timestamp to pasted image filenames to differentiate them
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#29524&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/mattermod" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F16344077%3Fv%3D4" alt="mattermod avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/mattermod" rel="noopener noreferrer"&gt;mattermod&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/mattermost/mattermost/issues/29524" rel="noopener noreferrer"&gt;&lt;time&gt;Dec 09, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The Problem&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;When pasting an image from the clipboard into the message input, it gets the filename &lt;code&gt;image.png&lt;/code&gt;. If multiple images are pasted, they all get the same &lt;code&gt;image.png&lt;/code&gt; filename. This can be a problem when downloading each file with the same name with danger of overwriting.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Proposed solution&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Auto-generate a Filename that includes the timestamp with this format:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;image-2024-11-18-6-29-57-PM&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Mattermost thread: &lt;a href="https://hub.mattermost.com/private-core/pl/xryg3tedg3bbxq3xuwnrj9ymyc" rel="nofollow noopener noreferrer"&gt;https://hub.mattermost.com/private-core/pl/xryg3tedg3bbxq3xuwnrj9ymyc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're interested please comment here and come &lt;a href="https://community.mattermost.com/core/channels/tickets" rel="nofollow noopener noreferrer"&gt;join our "Contributors" community channel&lt;/a&gt; on our daily build server, where you can discuss questions with community members and the Mattermost core team. For technical advice or questions, please  &lt;a href="https://community.mattermost.com/core/channels/developers" rel="nofollow noopener noreferrer"&gt;join our "Developers" community channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;New contributors please see our &lt;a href="https://developers.mattermost.com/contribute/getting-started/" rel="nofollow noopener noreferrer"&gt;Developer's Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;JIRA: &lt;a href="https://mattermost.atlassian.net/browse/MM-62003" rel="nofollow noopener noreferrer"&gt;https://mattermost.atlassian.net/browse/MM-62003&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mattermost/mattermost/issues/29524" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Issue 3: Mattermost - Improving SQL query maintainability and backward compatibility
&lt;/h3&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/mattermost/mattermost/issues/29548" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Avoid SELECT * in tokens_store.go
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#29548&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/mattermod" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F16344077%3Fv%3D4" alt="mattermod avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/mattermod" rel="noopener noreferrer"&gt;mattermod&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/mattermost/mattermost/issues/29548" rel="noopener noreferrer"&gt;&lt;time&gt;Dec 10, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;&lt;code&gt;SELECT *&lt;/code&gt; makes &lt;code&gt;ADD COLUMN&lt;/code&gt; a backwards incompatible schema change: older servers running against a newer schema won’t know what to do with the new columns.&lt;/p&gt;
&lt;p&gt;This ticket tracks the effort required to migrate the SQL queries in &lt;a href="https://github.com/mattermost/mattermost/blob/master/server/channels/store/sqlstore/tokens_store.go" rel="noopener noreferrer"&gt;https://github.com/mattermost/mattermost/blob/master/server/channels/store/sqlstore/tokens_store.go&lt;/a&gt; . (Please submit a single PR with changes to only this store.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Migrate any SELECT * queries written as strings into builder queries.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First, if the query is hard-coded as a string, e.g. &lt;code&gt;SELECT * FROM Table WHERE ...&lt;/code&gt;, migrate this query to using the SQLBuilder. So instead of this:&lt;/p&gt;
&lt;div class="highlight highlight-source-go js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-s1"&gt;_&lt;/span&gt;, &lt;span class="pl-s1"&gt;err&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;s&lt;/span&gt;.&lt;span class="pl-c1"&gt;GetReplica&lt;/span&gt;().&lt;span class="pl-c1"&gt;Get&lt;/span&gt;(&lt;span class="pl-s"&gt;"SELECT * FROM Table WHERE Id = ?"&lt;/span&gt;, &lt;span class="pl-s1"&gt;id&lt;/span&gt;); &lt;span class="pl-s1"&gt;err&lt;/span&gt; &lt;span class="pl-c1"&gt;!=&lt;/span&gt; &lt;span class="pl-c1"&gt;nil&lt;/span&gt; {
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;err&lt;/span&gt;
}&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;change it to this instead:&lt;/p&gt;
&lt;div class="highlight highlight-source-go js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-s1"&gt;query&lt;/span&gt; &lt;span class="pl-c1"&gt;:=&lt;/span&gt; &lt;span class="pl-s1"&gt;s&lt;/span&gt;.&lt;span class="pl-c1"&gt;getQueryBuilder&lt;/span&gt;().
    &lt;span class="pl-c1"&gt;Select&lt;/span&gt;(&lt;span class="pl-s"&gt;"*"&lt;/span&gt;).
    &lt;span class="pl-c1"&gt;From&lt;/span&gt;(&lt;span class="pl-s"&gt;"Table"&lt;/span&gt;).
    &lt;span class="pl-c1"&gt;Where&lt;/span&gt;(sq.&lt;span class="pl-smi"&gt;Eq&lt;/span&gt;{&lt;span class="pl-s"&gt;"Id"&lt;/span&gt;: &lt;span class="pl-s1"&gt;id&lt;/span&gt;})

&lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-s1"&gt;_&lt;/span&gt;, &lt;span class="pl-s1"&gt;err&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;s&lt;/span&gt;.&lt;span class="pl-c1"&gt;GetReplica&lt;/span&gt;().&lt;span class="pl-c1"&gt;GetBuilder&lt;/span&gt;(&lt;span class="pl-s1"&gt;query&lt;/span&gt;); &lt;span class="pl-s1"&gt;err&lt;/span&gt; &lt;span class="pl-c1"&gt;!=&lt;/span&gt; &lt;span class="pl-c1"&gt;nil&lt;/span&gt; {
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;err&lt;/span&gt;
}&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;It’s not necessary to change all queries in this [file: jus|file: ju]t the ones doing a &lt;code&gt;SELECT *&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Migrate any instances of&lt;/strong&gt; &lt;code&gt;SELECT *&lt;/code&gt; &lt;strong&gt;into explicitly enumerating the needed columns&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Instead of &lt;code&gt;SELECT("*")&lt;/code&gt;, rewrite to explicitly specify the columns needed:&lt;/p&gt;
&lt;div class="highlight highlight-source-go js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-s1"&gt;query&lt;/span&gt; &lt;span class="pl-c1"&gt;:=&lt;/span&gt; &lt;span class="pl-s1"&gt;s&lt;/span&gt;.&lt;span class="pl-c1"&gt;getQueryBuilder&lt;/span&gt;().
    &lt;span class="pl-c1"&gt;Select&lt;/span&gt;(&lt;span class="pl-s"&gt;"Column1"&lt;/span&gt;, &lt;span class="pl-s"&gt;"Column2"&lt;/span&gt;).
    &lt;span class="pl-c1"&gt;From&lt;/span&gt;(&lt;span class="pl-s"&gt;"Table"&lt;/span&gt;).
    &lt;span class="pl-c1"&gt;Where&lt;/span&gt;(sq.&lt;span class="pl-smi"&gt;Eq&lt;/span&gt;{&lt;span class="pl-s"&gt;"Id"&lt;/span&gt;: &lt;span class="pl-s1"&gt;id&lt;/span&gt;})&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;If these columns are referenced more than once in the file, factor out the query into the store constructor:&lt;/p&gt;
&lt;div class="highlight highlight-source-go js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;type&lt;/span&gt; &lt;span class="pl-smi"&gt;SqlTableStore&lt;/span&gt; &lt;span class="pl-k"&gt;struct&lt;/span&gt; {
    &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-smi"&gt;SqlStore&lt;/span&gt;

    &lt;span class="pl-c1"&gt;tableSelectQuery&lt;/span&gt; sq.&lt;span class="pl-smi"&gt;SelectBuilder&lt;/span&gt;
}

&lt;span class="pl-k"&gt;func&lt;/span&gt; &lt;span class="pl-s1"&gt;newSqlTableStore&lt;/span&gt;(&lt;span class="pl-s1"&gt;sqlStore&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-smi"&gt;SqlStore&lt;/span&gt;) store.&lt;span class="pl-smi"&gt;TableStore&lt;/span&gt; {
    &lt;span class="pl-s1"&gt;s&lt;/span&gt; &lt;span class="pl-c1"&gt;:=&lt;/span&gt; &lt;span class="pl-smi"&gt;SqlTableStore&lt;/span&gt;{
        &lt;span class="pl-s1"&gt;SqlStore&lt;/span&gt;: &lt;span class="pl-s1"&gt;sqlStore&lt;/span&gt;,
    }

    &lt;span class="pl-s1"&gt;s&lt;/span&gt;.&lt;span class="pl-c1"&gt;tableSelectQuery&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;s&lt;/span&gt;.&lt;span class="pl-c1"&gt;getQueryBuilder&lt;/span&gt;().
        &lt;span class="pl-c1"&gt;Select&lt;/span&gt;(&lt;span class="pl-s"&gt;"Column1"&lt;/span&gt;, &lt;span class="pl-s"&gt;"Column2"&lt;/span&gt;).
        &lt;span class="pl-c1"&gt;From&lt;/span&gt;(&lt;span class="pl-s"&gt;"Table"&lt;/span&gt;)

    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;amp;&lt;/span&gt;&lt;span class="pl-s1"&gt;s&lt;/span&gt;
}&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;and then extend it everywhere:&lt;/p&gt;
&lt;div class="highlight highlight-source-go js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-s1"&gt;query&lt;/span&gt; &lt;span class="pl-c1"&gt;:=&lt;/span&gt; &lt;span class="pl-s1"&gt;s&lt;/span&gt;.&lt;span class="pl-c1"&gt;tableSelectQuery&lt;/span&gt;.&lt;span class="pl-c1"&gt;Where&lt;/span&gt;(sq.&lt;span class="pl-smi"&gt;Eq&lt;/span&gt;{&lt;span class="pl-s"&gt;"Id"&lt;/span&gt;: &lt;span class="pl-s1"&gt;id&lt;/span&gt;})&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Run the related unit tests&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Within the &lt;code&gt;server/channels/store/sqlstore&lt;/code&gt; run the tests for the associated store, e.g. &lt;code&gt;go test -run TestTableStore&lt;/code&gt; (replace with the test for the store in question).&lt;/p&gt;

&lt;p&gt;If you're interested please comment here and come &lt;a href="https://community.mattermost.com/core/channels/tickets" rel="nofollow noopener noreferrer"&gt;join our "Contributors" community channel&lt;/a&gt; on our daily build server, where you can discuss questions with community members and the Mattermost core team. For technical advice or questions, please  &lt;a href="https://community.mattermost.com/core/channels/developers" rel="nofollow noopener noreferrer"&gt;join our "Developers" community channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;New contributors please see our &lt;a href="https://developers.mattermost.com/contribute/getting-started/" rel="nofollow noopener noreferrer"&gt;Developer's Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;JIRA: &lt;a href="https://mattermost.atlassian.net/browse/MM-62144" rel="nofollow noopener noreferrer"&gt;https://mattermost.atlassian.net/browse/MM-62144&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mattermost/mattermost/issues/29548" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How It Went
&lt;/h2&gt;

&lt;p&gt;I'll talk about the issues in order.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 1: Github CLI - Improving output formatting
&lt;/h3&gt;

&lt;p&gt;This issue was based on improving the output formatting for the &lt;code&gt;gh run view&lt;/code&gt; subcommand to bring it closer in line with &lt;a href="https://primer.style/" rel="noopener noreferrer"&gt;GitHub's design guidelines&lt;/a&gt; by displaying branch names in square brackets instead of parentheses.&lt;/p&gt;

&lt;p&gt;This issue was a much needed change of pace from the gargantuan issue I was working on for Mattermost. After struggling with the dev environment setup for days and failing, I needed something to get back into the flow of things and this issue was perfect.&lt;/p&gt;

&lt;p&gt;Setting up the dev environment was super simple because the only thing I needed to install was Go. I started, as always, by looking at the contributing docs, where I found a nice explanation of what goes in each project directory, which helped me find the file containing the subcommand's logic. I noticed the display function wasn't actually in that file and traced it back to a common utilities file for the &lt;code&gt;run&lt;/code&gt; command. From there, I just updated the display function to print square brackets instead of parentheses. I noticed it looked very reminiscent of C's &lt;code&gt;printf&lt;/code&gt;, which is apparently because Go is designed after C.&lt;/p&gt;

&lt;p&gt;Testing my changes manually was also very straightforward. It was a single command to build the binary, and then I could use it from the terminal. So I made the change and submitted my PR but forgot to run and update unit tests which I then corrected as soon as I realized.&lt;/p&gt;

&lt;p&gt;At this point the maintainer who opened the issue informed me that the issue hadn't been triaged yet and they weren't sure if they wanted to actually implement this. Fortunately, they later did agree on the changes, only with the additional acceptance criteria of also updating the formatting for the &lt;code&gt;gh codespace&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;So I made the changes - again, pretty straightforward process (Didn't forget to update the tests this time), and my changes were approved and merged. All in all, a pretty relaxed experience compared to other stuff I've worked on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 2: Mattermost - Adding timestamps to pasted image filenames
&lt;/h3&gt;

&lt;p&gt;For this issue, the maintainers noticed that images pasted from the clipboard would all receive the name "image.png", and wanted to add timestamps on paste, to help differentiate them in case they overwrite each other when downloading them.&lt;/p&gt;

&lt;p&gt;This seemed like it'd be a pretty straightforward issue, but actually ended up being pretty interesting, although me and the maintainers couldn't come to an agreement on the solution.&lt;/p&gt;

&lt;p&gt;The issue stemmed from the browser automatically assigning the file name "image.png" to clipboard images. Now, simply adding a check for "image.png" would be stupid simple, but of course it's never that easy. I found this &lt;a href="https://community.atlassian.com/t5/Confluence-questions/Inserting-an-image-from-the-clipboard-filename-does-not-get-a/qaq-p/2026325" rel="noopener noreferrer"&gt;thread on the Atlassian Confluence forums&lt;/a&gt; about a very similar issue. Confluence appended timestamps to images with a hardcoded check for the filename "image.png", but things broke when Firefox started localizing the filename, leading to German users ending up with the filename "grafik.png". &lt;/p&gt;

&lt;p&gt;Even though I manually tested the localization by switching Firefox to German and &lt;strong&gt;wasn't&lt;/strong&gt; able to reproduce it (i.e. it remained "image.png"), the possibility that the filename &lt;em&gt;could&lt;/em&gt; change at all on different platforms/environments meant I couldn't just hardcode the check.&lt;/p&gt;

&lt;p&gt;Another problem was that hardcoding the check meant if a user actually had a file named "image.png" we would end up modifying the filename which we didn't want to do. So, we needed a way to differentiate user-defined filenames and automatically generated filenames, without hardcoding them.&lt;/p&gt;

&lt;p&gt;Unfortunately, all we had to work with was a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent" rel="noopener noreferrer"&gt;ClipboardEvent&lt;/a&gt;, which didn't give us enough information to tell the difference. So it seems like the desired solution, where we wouldn't modify filenames unless they were automatically generated was not possible.&lt;/p&gt;

&lt;p&gt;I proposed an alternative where we could append timestamps to &lt;strong&gt;all files&lt;/strong&gt;, either on upload on download, maybe as a toggle-able setting, but this doesn't really directly address the issue. I've yet to hear back on what direction the maintainers want to go in, if they still want to implement this at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Issue 3: Mattermost - Improving SQL query maintainability and backward compatibility
&lt;/h3&gt;

&lt;p&gt;This issue stands out a bit among other issues I've worked on so far because it finally involves updating backend logic. The idea is to improve database queries by switching from &lt;code&gt;SELECT *&lt;/code&gt; to explicitly defining columns, ensuring backwards compatibility with database schema changes (older servers running against a newer schema won’t know what to do with the new columns). In addition, to improve maintainability, the queries were to be migrated from hardcoded strings to being constructed using an SQL query builder API.&lt;/p&gt;

&lt;p&gt;When I started working on this issue, I noticed the issue description talked about using a method called &lt;code&gt;getReplica()&lt;/code&gt; but that method didn't seem to exist, so I referenced an existing function in the same file that already used the query builder and used &lt;code&gt;getReplicaX()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order to find out what columns the table actually contained, I needed to go into the database and look around, but I noticed there were two database containers being spun up - MySQL and Postgres. I looked at the docs and saw that Postgres was preferred for new deployments and that there were in-app settings to choose the database, so I went into the settings to take a look and confirmed that Postgres was in fact selected, so I figured I should probably check out the Postgres container. I needed the database username so I went into the Docker Compose file and found an environment variable for it. I then used &lt;code&gt;docker exec&lt;/code&gt; to run &lt;code&gt;psql&lt;/code&gt; and find the table and it's columns.&lt;/p&gt;

&lt;p&gt;In order to figure out query builder syntax for selecting multiple columns, I searched the repo for the string &lt;code&gt;getQueryBuilder(&lt;/code&gt; and found an example at &lt;code&gt;server/channels/store/sqlstore/bot_store.go&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I also factored out the common query (&lt;code&gt;SELECT token, createat, type, extra FROM Tokens&lt;/code&gt;) into the type and it's constructor like the issue said and modified the other queries to use the newly factored-out query.&lt;/p&gt;

&lt;p&gt;So I made the pull request, but I realized the maintainer ended up updating the file I was working on after I'd made my branch, and this led to merge conflicts. Following their contribution guidelines, instead of rebasing I merged master into my branch. Remember how I couldn't find the &lt;code&gt;getReplica()&lt;/code&gt; method? They'd updated the file to now use that method. This method had different syntax so I had to go and look for examples so I could update my changes while resolving the merge conflict.&lt;/p&gt;

&lt;p&gt;This PR is still pending review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;In this process, I was exposed to Go, psql, and Web APIs like &lt;code&gt;ClipboardEvent&lt;/code&gt; and &lt;code&gt;DataTransferItem&lt;/code&gt;, which made for a fun learning experience. In fact, I ended up working with Go in two out of three of the issues which I thought was interesting. Seems like Go is growing in popularity.&lt;/p&gt;

&lt;p&gt;That's about it for this post. This also marks the end of the course I'm taking on Open Source Development, OSD600 at Seneca Polytechnic. It's been a fantastic journey starting from barely understanding how to use Git to being able to use it to effectively contribute to huge projects. The course may be over but I'm certain I'll continue to work in open source in the future. Thanks for reading.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
