<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: TheoForger</title>
    <description>The latest articles on DEV Community by TheoForger (@theoforger).</description>
    <link>https://dev.to/theoforger</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%2F2037689%2F0c54d772-8a7c-4401-a55e-fb9f4995fcf1.png</url>
      <title>DEV Community: TheoForger</title>
      <link>https://dev.to/theoforger</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theoforger"/>
    <language>en</language>
    <item>
      <title>Closing the Chapter - Recap</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Thu, 17 Apr 2025 19:55:24 +0000</pubDate>
      <link>https://dev.to/theoforger/closing-the-chapter-recap-mhd</link>
      <guid>https://dev.to/theoforger/closing-the-chapter-recap-mhd</guid>
      <description>&lt;p&gt;It's finally the end of semester. This also marks the end of the second open source course for me. Looking back, there are a lot to reflect on.&lt;/p&gt;

&lt;p&gt;Looking at my entire program thus far. I can comfortably say I've learned much more in these two courses than everything else combined. As I mentioned in &lt;a href="https://dev.to/theoforger/december-so-far-recap-4kce"&gt;last semester's recap&lt;/a&gt;, learning to code from school feels very "fragmented". It's like you collected all these puzzle pieces but don't have a reference picture to follow. Open source was just the epiphany I needed to make sense of these concepts as a whole.&lt;/p&gt;

&lt;p&gt;I've learned so much from these two courses. And it goes way beyond just coding skills too. I can't possibly cover everything here, but I'll go through some of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  🦀 My Rust Journey
&lt;/h2&gt;

&lt;p&gt;I started learning Rust about two years ago, way before I took this course. However, I was mostly following YouTube tutorials and copying whatever they did. I loved the language, and it was a lot of fun, but without actually building something with the language, it was hard to get a sense of the hows and the whys of the mechanics.&lt;/p&gt;

&lt;p&gt;It wasn't until the &lt;a href="https://github.com/theoforger/mastermind" rel="noopener noreferrer"&gt;Mastermind&lt;/a&gt; project which I created for the previous course, that I really started to understand Rust. Because I was starting a project from scratch, I had to pay attention to things like design patterns, modules, access control, but also details like memory management, pattern matching syntax, where I really learned to appreciate the ownership system in Rust.&lt;/p&gt;

&lt;p&gt;Working on something tangible gave me the incentives to keep learning and improving my code, instead of just aiming to finish an assignment. During that couple of months, I studied more about traits and generic types in my own time, so that I could use them in my project. I also familiarized myself with the Rust ecosystem, like &lt;code&gt;rustup&lt;/code&gt;, &lt;code&gt;cargo&lt;/code&gt;, and &lt;code&gt;clippy&lt;/code&gt;. All these wonderful first-party tools that made Rust a blessing to work with.&lt;/p&gt;

&lt;p&gt;The second push was me getting into the Hurl project. This was where I got to know Rust in action. Looking at the &lt;a href="https://github.com/search?q=author%3Atheoforger+repo%3AOrange-OpenSource%2Fhurl&amp;amp;type=pullrequests" rel="noopener noreferrer"&gt;GitHub search result&lt;/a&gt;, I have submitted 15 PRs in Hurl's repo, with more to come in the future. For each of them, I went all in with code reading, researching, learning. I was exposed to all kinds of technologies like Rust, libcurl, and the HTTP protocol. This is not only a much more valuable experience than learning at school, but also more rewarding.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚒️ Working With Git and GitHub
&lt;/h2&gt;

&lt;p&gt;Another great skill I learned was Git. I used to have this mindset (I'm sure many others do too) that Git was just there to make your life more miserable in exchange for a respawn point when you completely f*ed up your code. According to my professor, most programmers are not comfortable with Git, some of which claiming that their code is "lost" in it.&lt;/p&gt;

&lt;p&gt;Throughout these two semesters, I worked a lot with Git. For my own projects, for my teammate's projects, and for other projects I contributed to. I went from "pushing and pulling from main" to having &lt;code&gt;git checkout&lt;/code&gt;, &lt;code&gt;git merge&lt;/code&gt; and &lt;code&gt;git rebase&lt;/code&gt; in my daily vocabulary. Using these commands now feels like a second nature. Of course, there are still situations where I feel lost, but I learned not to panic about it. With enough patience and some digging with &lt;code&gt;git log&lt;/code&gt; or &lt;code&gt;git reflog&lt;/code&gt;, I can always find my way back eventually.&lt;/p&gt;

&lt;p&gt;I also got quite comfortable with GitHub. Whether it's creating issues, making pull requests, or reviewing code, or making followup changes to a review. I learned to communicate asynchronously with maintainers: Always provide enough context, and respond with actionable comments. In addition, I worked extensively with GitHub Actions to set up CI/CD pipelines on my own project, and to test my code for projects I contributed to.&lt;/p&gt;

&lt;p&gt;All these are valuable lessons I could never have learned from lectures and assignments.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❤️ Personal Takeaways
&lt;/h2&gt;

&lt;p&gt;This semester definitely had its ups and downs. There were times I felt like I achieved a lot, and times where everybody seemed to be stuck or distracted. But overall, I am very proud of my continuous work on Hurl, as well as the efforts I put into maintaining Starchart.&lt;/p&gt;

&lt;p&gt;Getting into a project was the hardest part. You had to assess the project enough to make sure they welcome contributions, and read the issues enough to find something you can work on, and then understand the code enough to work on these issues. Finally, you had to fight your inner demons and work up your courage to submit your first PR - Then it gets easier from there, but it's always hard at the beginning.&lt;/p&gt;

&lt;p&gt;Despite some improvements compared to the very beginning, I still don't feel good about my demos. Something about talking in a conference call makes my thoughts incredibly disorganized. I forget to slow down, forget to breath, and sometimes forget my lines completely.&lt;/p&gt;

&lt;p&gt;Last but not the least, I want to say thank you to my wonderful professor &lt;a href="https://github.com/humphd" rel="noopener noreferrer"&gt;David&lt;/a&gt;. You have your way of inspiring your students by encouraging us to work on what we're interested in. You gave us freedom to explore and experiment on our own, but also support when we needed it. It's not an exaggeration to say these two courses have been life changing for me, and none of this was possible without you!&lt;/p&gt;

&lt;p&gt;That's it folks. See you again in open source!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Sprint 5 - Chakra UI v3 Migration</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Wed, 16 Apr 2025 20:59:58 +0000</pubDate>
      <link>https://dev.to/theoforger/sprint-5-chakra-ui-v3-migration-4pfi</link>
      <guid>https://dev.to/theoforger/sprint-5-chakra-ui-v3-migration-4pfi</guid>
      <description>&lt;p&gt;For the last sprint I focused on &lt;a href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;Starchart&lt;/a&gt; since I haven't got a response from &lt;a href="https://github.com/Orange-OpenSource/hurl" rel="noopener noreferrer"&gt;Hurl&lt;/a&gt; just yet. This week I saw more and more CVEs popping up for Chakra UI v2's dependencies So I gave it a second attempt to migrate to v3. Spoiler alert: It was a nightmare.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/895" 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;
        [WIP] Upgrade chakra-ui to v3
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#895&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/895" rel="noopener noreferrer"&gt;&lt;time&gt;Apr 03, 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;&lt;code&gt;chakra-ui&lt;/code&gt; version 3 introduced many breaking changes. This PR is an attempt to upgrade&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Changes&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Removed &lt;code&gt;@emotion/styled&lt;/code&gt;, &lt;code&gt;framer-motion&lt;/code&gt;, &lt;code&gt;@chakra-ui/icons&lt;/code&gt;(migrated to &lt;code&gt;react-icons&lt;/code&gt; since chakra stopped supporting their icons library)&lt;/li&gt;
&lt;li&gt;Modified &lt;code&gt;tsconfig.json&lt;/code&gt; to &lt;a href="https://www.chakra-ui.com/docs/get-started/frameworks/remix#update-tsconfig" rel="nofollow noopener noreferrer"&gt;target &lt;code&gt;ESNext&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Add &lt;a href="https://www.chakra-ui.com/docs/get-started/migration#update-packages" rel="nofollow noopener noreferrer"&gt;code snippet&lt;/a&gt; from chakra&lt;/li&gt;
&lt;li&gt;Refactored theme to use &lt;a href="https://www.chakra-ui.com/docs/get-started/migration#refactor-custom-theme" rel="nofollow noopener noreferrer"&gt;systems&lt;/a&gt; instead&lt;/li&gt;
&lt;li&gt;Changed component names and structures (the &lt;a href="https://www.chakra-ui.com/docs/get-started/migration#component-changes" rel="nofollow noopener noreferrer"&gt;migration guide&lt;/a&gt; is not complete on this matter)&lt;/li&gt;
&lt;li&gt;Dropped &lt;code&gt;useToast&lt;/code&gt; hook in favor of &lt;a href="https://www.chakra-ui.com/docs/components/toast" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;toaster&lt;/code&gt;&lt;/a&gt; from the code snippet&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/895" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  What Changes Did I Encounter?
&lt;/h2&gt;

&lt;p&gt;In short, everything has changed. From dependencies, components, props, to syntax, configuration schema, even font size and theme. It was essentially a rewrite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependencies
&lt;/h3&gt;

&lt;p&gt;Chakra UI v3 doesn't rely on &lt;code&gt;framer-motion&lt;/code&gt; for animation anymore. It needed to be removed, among some other changes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm uninstall @emotion/styled framer-motion
npm &lt;span class="nb"&gt;install&lt;/span&gt; @chakra-ui/react@latest @emotion/react@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They also introduced some code snippet to supplement some of the changes in this update. I'll go through them later, but here's how you add the snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @chakra-ui/cli snippet add
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Component Names and Behavior
&lt;/h3&gt;

&lt;p&gt;Component Changes happened all across the board. Generally, namespaces are used to replace child components. Some are simple name changes, for example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;v2&lt;/th&gt;
    &lt;th&gt;v3&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;
      &lt;pre&gt;
&amp;lt;TableContainer&amp;gt;
  &amp;lt;Table&amp;gt;
    &amp;lt;Thead&amp;gt;
      &amp;lt;Tr&amp;gt;
        &amp;lt;Th/&amp;gt;
      &amp;lt;/Tr&amp;gt;
    &amp;lt;/Thead&amp;gt;
    &amp;lt;Tbody&amp;gt;
      &amp;lt;Tr&amp;gt;
        &amp;lt;Td/&amp;gt;
      &amp;lt;/Tr&amp;gt;
    &amp;lt;/Tbody&amp;gt;
    &amp;lt;Tfoot&amp;gt;
      &amp;lt;Tr&amp;gt;
        &amp;lt;Th/&amp;gt;
      &amp;lt;/Tr&amp;gt;
    &amp;lt;/Tfoot&amp;gt;
  &amp;lt;/Table&amp;gt;
&amp;lt;/TableContainer&amp;gt;
      &lt;/pre&gt;
    &lt;/td&gt;
    &lt;td&gt;
      &lt;pre&gt;
&amp;lt;Table.Root&amp;gt;
  &amp;lt;Table.Header&amp;gt;
    &amp;lt;Table.Row&amp;gt;
      &amp;lt;Table.ColumnHeader /&amp;gt;
    &amp;lt;/Table.Row&amp;gt;
  &amp;lt;/Table.Header&amp;gt;
  &amp;lt;Table.Body&amp;gt;
    &amp;lt;Table.Row&amp;gt;
      &amp;lt;Table.Cell /&amp;gt;
    &amp;lt;/Table.Row&amp;gt;
  &amp;lt;/Table.Body&amp;gt;
  &amp;lt;Table.Footer&amp;gt;
    &amp;lt;Table.Row&amp;gt;
      &amp;lt;Table.Cell /&amp;gt;
    &amp;lt;/Table.Row&amp;gt;
  &amp;lt;/Table.Footer&amp;gt;
&amp;lt;/Table.Root&amp;gt;
      &lt;/pre&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;However, many of them also has different behavior and expect different structures. For instance:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;v2&lt;/th&gt;
    &lt;th&gt;v3&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;
      &lt;pre&gt;
&amp;lt;Tabs&amp;gt;
  &amp;lt;TabList&amp;gt;
    &amp;lt;Tab&amp;gt;One&amp;lt;/Tab&amp;gt;
    &amp;lt;Tab&amp;gt;Two&amp;lt;/Tab&amp;gt;
    &amp;lt;Tab&amp;gt;Three&amp;lt;/Tab&amp;gt;
  &amp;lt;/TabList&amp;gt;

  &amp;lt;TabPanels&amp;gt;
    &amp;lt;TabPanel&amp;gt;
      &amp;lt;p&amp;gt;one!&amp;lt;/p&amp;gt;
    &amp;lt;/TabPanel&amp;gt;
    &amp;lt;TabPanel&amp;gt;
      &amp;lt;p&amp;gt;two!&amp;lt;/p&amp;gt;
    &amp;lt;/TabPanel&amp;gt;
    &amp;lt;TabPanel&amp;gt;
      &amp;lt;p&amp;gt;three!&amp;lt;/p&amp;gt;
    &amp;lt;/TabPanel&amp;gt;
  &amp;lt;/TabPanels&amp;gt;
&amp;lt;/Tabs&amp;gt;
&lt;/pre&gt;
    &lt;/td&gt;
    &lt;td&gt;
      &lt;pre&gt;
&amp;lt;Tabs.Root&amp;gt;
  &amp;lt;Tabs.List&amp;gt;
    &amp;lt;Tabs.Trigger value="one"&amp;gt;
      one
    &amp;lt;/Tabs.Trigger&amp;gt;
    &amp;lt;Tabs.Trigger value="two"&amp;gt;
      two
    &amp;lt;/Tabs.Trigger&amp;gt;
    &amp;lt;Tabs.Trigger value="three"&amp;gt;
      three
    &amp;lt;/Tabs.Trigger&amp;gt;
  &amp;lt;/Tabs.List&amp;gt;
  &amp;lt;Tabs.Content value="one"&amp;gt;one!&amp;lt;/Tabs.Content&amp;gt;
  &amp;lt;Tabs.Content value="two"&amp;gt;two!&amp;lt;/Tabs.Content&amp;gt;
  &amp;lt;Tabs.Content value="three"&amp;gt;three!&amp;lt;/Tabs.Content&amp;gt;
&amp;lt;/Tabs.Root&amp;gt;
&lt;/pre&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you can see, Tabs in v2 sequentially maps a  from  to  in , while in v3 it requires a &lt;code&gt;value&lt;/code&gt;, in addition to all the name changes.&lt;/p&gt;

&lt;p&gt;There are many other changes like these. Unfortunately the only way to handle them is to look at the documentation for both versions and compare the differences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Props
&lt;/h3&gt;

&lt;p&gt;There are changes in both the name of some props, and what props are expected for certain components.&lt;/p&gt;

&lt;p&gt;For one, some boolean typed props now have a simpler name. For example, &lt;code&gt;isOpen&lt;/code&gt; became &lt;code&gt;open&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The other type of change is also the more challenging type. For example the &lt;code&gt;&amp;lt;Card&amp;gt;&lt;/code&gt; component changed the available variants you can use, and silently dropped support for some styling props like &lt;code&gt;align&lt;/code&gt;. Some of them are related to some other grand schema changes, but just like the components, the only way to figure them out is to compare the documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Theme Configuration
&lt;/h3&gt;

&lt;p&gt;In Chakra UI v3, &lt;code&gt;theme&lt;/code&gt;s are included as a part of &lt;code&gt;system&lt;/code&gt;, as apposed to a standalone configuration option in v2. The new &lt;code&gt;theme&lt;/code&gt; object expects a completely different schema too.&lt;/p&gt;

&lt;p&gt;In addition, component-specific style override in v2 is replaced by &lt;a href="https://chakra-ui.com/docs/theming/recipes" rel="noopener noreferrer"&gt;&lt;code&gt;recipe&lt;/code&gt;&lt;/a&gt;s.&lt;/p&gt;

&lt;p&gt;So for the Starchart project, the configuration went from:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extendTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;breakpoints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;defineStyleConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;baseStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;brand.500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;textDecor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;underline&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="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;withDefaultColorScheme&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;colorScheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;brand&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;to&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;recipes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;defineRecipe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;textDecor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;underline&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="na"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;breakpoints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;semanticTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;solid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand.500}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;contrast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;fg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand.700}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;muted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand.100}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand.200}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;emphasized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand.300}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;focusRing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand.500}&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;brand_gray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;solid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand_gray.500}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;contrast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;colors.brand_gray.100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;fg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand_gray.700}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;muted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand_gray.100}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand_gray.200}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;emphasized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand_gray.300}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;focusRing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{colors.brand_gray.500}&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="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;globalCss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;styles&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;h3&gt;
  
  
  Toast
&lt;/h3&gt;

&lt;p&gt;In Chakra UI v2, Toast is used &lt;a href="https://v2.chakra-ui.com/docs/components/toast/usage" rel="noopener noreferrer"&gt;via a hook&lt;/a&gt;. However, in v3 it's replaced by the &lt;a href="https://chakra-ui.com/docs/components/toast" rel="noopener noreferrer"&gt;&lt;code&gt;toaster&lt;/code&gt;&lt;/a&gt; code snippet. In the new version, you need to import both &lt;code&gt;Toaster&lt;/code&gt; and &lt;code&gt;toaster&lt;/code&gt; from the snippet, place the &lt;code&gt;&amp;lt;Toaster /&amp;gt;&lt;/code&gt; component somewhere on the page, and then use &lt;code&gt;toaster&lt;/code&gt; to trigger them. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Toaster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toaster&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;~/components/ui/toaster&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;useEffect&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;copied&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;toaster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&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="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; was copied to the clipboard`&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;success&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;copied&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="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// page content...&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Toaster&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dropping &lt;code&gt;chakra-ui/icon&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@chakra-ui/icons" rel="noopener noreferrer"&gt;@chakra-ui/icons&lt;/a&gt; is deprecated in Chakra UI v3. There are a couple of replacements but I decided to migrate to &lt;code&gt;react-icons&lt;/code&gt;, since it was already in use for other parts of the project.&lt;/p&gt;

&lt;p&gt;To migrate, you need to wrap the icon component from your library of choice with &lt;code&gt;&amp;lt;Link&amp;gt;...&amp;lt;/Link&amp;gt;&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Download icon&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Icon&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"md"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FaDownload&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's Still Broken?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Custom Breakpoints
&lt;/h3&gt;

&lt;p&gt;In Chakra UI, you can define &lt;a href="https://chakra-ui.com/docs/theming/customization/breakpoints" rel="noopener noreferrer"&gt;custom breakpoints&lt;/a&gt; like so:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;breakpoints&lt;/span&gt; &lt;span class="o"&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;xs&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;20em&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;sm&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;30em&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;md&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;48em&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;lg&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;62em&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;xl&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;80em&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;2xl&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;96em&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;However, despite including this configuration in my custom theme, I still get type error in places where custom breakpoints are used:&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%2F7k505y1kqw77z36t3sq3.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%2F7k505y1kqw77z36t3sq3.png" alt="GitHub Actions error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Animation
&lt;/h3&gt;

&lt;p&gt;Animation is broken after this upgrade, possibly due to the deprecation of &lt;code&gt;framer-motion&lt;/code&gt;. However, from my testing, the animation issue does not seem to persist once React is updated to 19.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mobile Layout
&lt;/h3&gt;

&lt;p&gt;Other than some inconsistent breakpoints behavior, some UI elements are not in the correct place in mobile layout. For example:&lt;/p&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;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%2F54l8mo7oevc1rg1embhn.png" alt="before"&gt;&lt;/td&gt;
&lt;td&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%2F4uhrolfpsckp8x1ud82b.png" alt="after"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Real Problem
&lt;/h2&gt;

&lt;p&gt;The most difficult aspect of this migration was not the changes themselves. It was the lack of documentation for them. Although they provide a &lt;a href="https://www.chakra-ui.com/docs/get-started/migration#refactor-custom-theme" rel="noopener noreferrer"&gt;migration guide&lt;/a&gt;, it's far from complete.&lt;/p&gt;

&lt;p&gt;Just to name a few:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The guide doesn't cover most changes in the component names. Some components have completely overhauled their structures (For example &lt;code&gt;&amp;lt;Tabs&amp;gt;&lt;/code&gt;), and it's not mentioned either.&lt;/li&gt;
&lt;li&gt;Many components changed the props they expect, most of which are not mentioned in the guide.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;Toast&amp;gt;&lt;/code&gt; went from a hook to a code snippet, and it's not mentioned.&lt;/li&gt;
&lt;li&gt;Font sizes are completely changed, which is not mentioned in the guide.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;Hide&amp;gt;&lt;/code&gt; component is removed and the behavior changed in &lt;code&gt;&amp;lt;Show&amp;gt;&lt;/code&gt; as well. Neither of them is documented.&lt;/li&gt;
&lt;li&gt;Component-specific style override is replaced by recipes. It's not covered by the guide.
...&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, this section is not meant as an attack on the Chakra UI project, but a reminder that a significant upgrade like this really needs a comprehensive migration guide. An automation tool would also be nice, like what React did with &lt;a href="https://github.com/reactjs/react-codemod" rel="noopener noreferrer"&gt;&lt;code&gt;react-codemod&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Sprint 5 - Mischief Happens</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Thu, 27 Mar 2025 14:39:08 +0000</pubDate>
      <link>https://dev.to/theoforger/sprint-5-mischief-happens-2k9f</link>
      <guid>https://dev.to/theoforger/sprint-5-mischief-happens-2k9f</guid>
      <description>&lt;p&gt;This week I did some more incremental work on Hurl, finalizing the &lt;code&gt;redirects&lt;/code&gt; query. On Startchart, I messed up a couple of things, fixed a couple of things and learned a couple of lessons!&lt;/p&gt;

&lt;h2&gt;
  
  
  Hurl
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Add query for HTTP redirects (&lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3916" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Last week, I enabled the code to pass down necessary information about HTTP redirections to queries. Continuing on that, I've been working on the &lt;code&gt;redirects&lt;/code&gt; query itself. &lt;/p&gt;

&lt;p&gt;Going back to the expected behavior proposed by the maintainer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET http://foo.com
HTTP 200
[Asserts]
redirects count == 2
redirects nth 0 url == "http://bar.com"
redirects nth 0 status == 302
redirects nth 1 url == "http://baz.com"
redirects nth 1 status == 302
url == "http://baz.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The query is treated like a list, you can perform assertions on the list itself, or get the individual HTTP redirect by index, and then assert on that.&lt;/p&gt;

&lt;p&gt;Looking at the code one more time, they already had a &lt;code&gt;Value::List(Vec&amp;lt;Value&amp;gt;)&lt;/code&gt; variant, and queries like &lt;code&gt;count&lt;/code&gt; and &lt;code&gt;nth&lt;/code&gt; were already implemented, so all I had left to do was to create another &lt;code&gt;Value&lt;/code&gt; variant for HTTP redirection.&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;// `runner::HttpResponse`&lt;/span&gt;
&lt;span class="c1"&gt;// Name suggested by the maintainer &lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&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;and then&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="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="nf"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And then came my favorite part about working in Rust, which was when the compiler told me everywhere else that needs to be changed.&lt;/p&gt;

&lt;p&gt;For the evaluation method itself, a.k.a. the place where everything came together, I processed the passed-down responses into &lt;code&gt;runner::HttpResponse&lt;/code&gt;. I popped the final response which was not considered a redirect. And finally, I constructed them into a &lt;code&gt;Value::List&lt;/code&gt;. Here's the result:&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="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;eval_redirects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;QueryResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt;
        &lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="py"&gt;.url&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="py"&gt;.status&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="nf"&gt;.pop&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="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&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;
  
  
  Startchart
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Some &lt;code&gt;package-lock.json&lt;/code&gt; Shenanigans
&lt;/h3&gt;

&lt;p&gt;Never merge anything without testing first.&lt;/p&gt;

&lt;p&gt;Last week, I merged &lt;a href="https://github.com/DevelopingSpace/starchart/pull/842" rel="noopener noreferrer"&gt;a PR from my co-maintainer Uday&lt;/a&gt;. I didn't think it needed more testing since I had already reviewed it before, and there was only a rebase since then. Plus, the CI pipelines were all green.&lt;/p&gt;

&lt;p&gt;Only after that did I realize, although the production build worked just fine, I couldn't run the dev build anymore. There were errors about missing dependencies:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
node:internal/modules/cjs/loader:1244
  const err = new Error(message);
              ^

Error: Cannot find module 'colorspace'
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I made a new clone of the project and set up everything from scratch. Still the same result. I messaged Uday to confirmed it. And or course, it worked on his machine 😆. We decided to &lt;a href="https://github.com/DevelopingSpace/starchart/pull/872" rel="noopener noreferrer"&gt;revert the PR&lt;/a&gt; and investigate.&lt;/p&gt;

&lt;p&gt;We spent the next couple of hours trying to reproduce and fix this, and eventially we narrowed it down to &lt;code&gt;package-lock.json&lt;/code&gt;: We were only able to properly run the dev build if we used &lt;code&gt;npm -ci&lt;/code&gt; instead of &lt;code&gt;npm -i&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then Uday had the idea to simply delete the lock file and re-generate it. We tried it and &lt;a href="https://github.com/DevelopingSpace/starchart/pull/873" rel="noopener noreferrer"&gt;it worked&lt;/a&gt;! This time, of course, I learned the lesson and carefully tested everything.&lt;/p&gt;
&lt;h3&gt;
  
  
  Update on React hydration errors
&lt;/h3&gt;

&lt;p&gt;Ever since this issue was created, I'd never been able to recreate it. I tried different browsers, different builds - nothing.&lt;/p&gt;

&lt;p&gt;This came as a happy accident. I once left the site open overnight, and when I came back, all the stylesheets were gone! I immediately opened up the console. The first thing I noticed: There wasn't any warning of CSP this time.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/issues/845#issuecomment-2743450682" 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;
        Comment for
      &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/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; commented on &lt;a href="https://github.com/DevelopingSpace/starchart/issues/845#issuecomment-2743450682" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 21, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;I finally ran into this issue after leaving the "DNS records" page open and idle overnight. And other pages seemed to load just fine. It might not be related to CSP after all, since I didn't see the error message here.&lt;/p&gt;
&lt;p&gt;Strangely, every time I refresh, the style sheet seems to load for a split second and then unloads itself:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/user-attachments/assets/0299d9f7-9fe4-43fc-aa18-38320533542f" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/0299d9f7-9fe4-43fc-aa18-38320533542f&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#issuecomment-2743450682" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;I couldn't quite figure out what happened but I decided to look into the behavior even more. Here's what I found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The stylesheet was only broken on this particular page a.k.a. &lt;code&gt;/dns-records&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Every time I refresh, the stylesheet loads for a split second and then unloads itself. (Maybe something to do with cache?)&lt;/li&gt;
&lt;li&gt;I could navigate to other pages and then back. In this case everything would load normally, but as soon as I refresh, the stylesheet was gone again.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fix certificate content (&lt;a href="https://github.com/DevelopingSpace/starchart/pull/878" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;I found this issue a while ago when I was looking into some &lt;a href="https://github.com/DevelopingSpace/starchart/issues/766" rel="noopener noreferrer"&gt;certificate related issue&lt;/a&gt;. In short, the certificate files from the download links didn't have the correct information inside.&lt;/p&gt;

&lt;p&gt;I looked into this expecting it to be some edge-case bug. But it really didn't take me long to find the problem inside the download handler:&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="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;certificate&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="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;certificate&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="nx"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.certificate.pem`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;privateKey&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="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;privateKey&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="nx"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.privkey.pem`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chain&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="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;certificate&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="nx"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.chain.pem`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fullChain&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="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;certificate&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="nx"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.bundle.pem`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This turned out to be a much simpler fix than I anticipated - The handler was grabbing the wrong content: In case of &lt;code&gt;chain&lt;/code&gt; and &lt;code&gt;fullChain&lt;/code&gt;, it was serving the end-entity certificate instead.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
      <category>rust</category>
    </item>
    <item>
      <title>Sprint 4 - I'm Finally Making Sense of Hurl</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Thu, 20 Mar 2025 14:34:39 +0000</pubDate>
      <link>https://dev.to/theoforger/sprint-4-im-finally-making-sense-of-hurl-18kh</link>
      <guid>https://dev.to/theoforger/sprint-4-im-finally-making-sense-of-hurl-18kh</guid>
      <description>&lt;p&gt;It's the end of Sprint 4. I'm happy to say that I finally find my groove working on Hurl. And as usual, I also did some chores on the Starchart project.&lt;/p&gt;

&lt;h2&gt;
  
  
  🦀🌐 Hurl
&lt;/h2&gt;

&lt;p&gt;This week I've been working towards a &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/922" rel="noopener noreferrer"&gt;feature request&lt;/a&gt; to enable queries on HTTP redirects. Same as before, every time I worked on something new, I was faced with all sorts of confusions. But this time I decided to do more code reading and try to understand it even more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Reading
&lt;/h3&gt;

&lt;p&gt;I started with a &lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3050/files" rel="noopener noreferrer"&gt;similar PR&lt;/a&gt;, hoping to find some inspiration. Then I quickly realized this PR only focuses on evaluating the queries, and this feature goes beyond that.&lt;/p&gt;

&lt;p&gt;Instead, I followed my intuition to a file I already worked on - the HTTP client file &lt;code&gt;hurl::http::client&lt;/code&gt;. I wasn't sure if it's related, but I knew that it was involved in this request and response process. Using the IDE, I followed the trail of where each function was used and eventually constructed a few diagrams to help me understand things:&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%2F9sixn6lbestrbyxjcq1f.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%2F9sixn6lbestrbyxjcq1f.png" alt="call processing" width="800" height="722"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The diagram above illustrates the basic process of everything involved from the moment when the Hurl file is parsed, to when HTTP requests are made. The green blocks represent function calls, and the red ones are for return values.&lt;/p&gt;

&lt;p&gt;Hurl files are first parsed into &lt;code&gt;entries&lt;/code&gt;. Each &lt;code&gt;entry&lt;/code&gt; contains one &lt;code&gt;call&lt;/code&gt; if there's no redirections, or multiple &lt;code&gt;call&lt;/code&gt;s if there is. And each &lt;code&gt;call&lt;/code&gt; contains a pair of HTTP request and response.&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%2Fcwqpo5k2em6rjhkddh8e.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%2Fcwqpo5k2em6rjhkddh8e.png" alt="capture evaluation" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hurl uses the final &lt;code&gt;call&lt;/code&gt; in &lt;code&gt;Vec&amp;lt;Call&amp;gt;&lt;/code&gt; to further evaluate information for captures and asserts. The diagram above only shows the capture evaluation process, but assert is similar.&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%2Fh2leiedc2sdgxjuefqr3.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%2Fh2leiedc2sdgxjuefqr3.png" alt="data structure" width="800" height="721"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a (partial) diagram of the data structures involved in the previous process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working on the Feature (&lt;a href="https://github.com/Orange-OpenSource/hurl/issues/922#issuecomment-2739629431" rel="noopener noreferrer"&gt;Link to PR&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;In order to evaluate redirections, I need the knowledge of all the HTTP requests made in the whole request chain. Looking at the diagrams, the last place with the said knowledge is &lt;code&gt;entry::run&lt;/code&gt; - since &lt;code&gt;Vec&amp;lt;Call&amp;gt;&lt;/code&gt; is returned to this function, and each &lt;code&gt;Call&lt;/code&gt; only contains one request. In other words, &lt;code&gt;entry::run&lt;/code&gt; is probably where I should work on.&lt;/p&gt;

&lt;p&gt;Looking at the code, the actual queries are not evaluated until &lt;code&gt;query::eval_query&lt;/code&gt;, but the entire chain of &lt;code&gt;Vec&amp;lt;Call&amp;gt;.last()&lt;/code&gt; -&amp;gt; &lt;code&gt;http::Response&lt;/code&gt; -&amp;gt; &lt;code&gt;response::eval_captures&lt;/code&gt; -&amp;gt; &lt;code&gt;capture::eval_capture&lt;/code&gt; -&amp;gt; &lt;code&gt;query::eval_query&lt;/code&gt; only knows the final HTTP request. I had to figured out a way to pass the knowledge of others down the chain. To achieve this, I thought of 2 solutions:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/922#issuecomment-2738349600" 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;
        Comment for
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#922&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; commented on &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/922#issuecomment-2738349600" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 19, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;@jcamiel Hello! I dug into the code quite a bit. Right now, because our &lt;code&gt;response::eval_captures&lt;/code&gt; and &lt;code&gt;response::eval_asserts&lt;/code&gt; methods accept one HTTP request, we only use the response from the last call:
&lt;a href="https://github.com/Orange-OpenSource/hurl/blob/95a2cc55dd318a0a24ac0f3c88245883878853a9/packages/hurl/src/runner/entry.rs#L130-L132" rel="noopener noreferrer"&gt;https://github.com/Orange-OpenSource/hurl/blob/95a2cc55dd318a0a24ac0f3c88245883878853a9/packages/hurl/src/runner/entry.rs#L130-L132&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since we need all the HTTP requests in order to retrieve the redirects, I can think of two solutions to this. Let me know which one you prefer (or something else):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make a helper function to extract all the HTTP responses from a list of calls, and modify &lt;code&gt;response::eval_captures&lt;/code&gt; and &lt;code&gt;response::eval_asserts&lt;/code&gt; to accept &lt;code&gt;&amp;amp;[&amp;amp;http::Response]&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;Modify &lt;code&gt;http::Response&lt;/code&gt; to include a list of redirections (or a list of references to the previous responses?)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Really appreciate your input 🙏&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/issues/922#issuecomment-2738349600" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The maintainer picked the first one and gave me &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/922#issuecomment-2739629431" rel="noopener noreferrer"&gt;some extra help&lt;/a&gt;. And that was all I needed to work on my first PR!&lt;/p&gt;

&lt;h3&gt;
  
  
  Clippy Corner
&lt;/h3&gt;

&lt;p&gt;I'm officially making this a segment because every time I work on Rust, clippy always finds a way to improve my code.&lt;/p&gt;

&lt;p&gt;This time, I got a warning of &lt;a href="https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec" rel="noopener noreferrer"&gt;&lt;code&gt;#useless_vec&lt;/code&gt;&lt;/a&gt; due to the usage of &lt;code&gt;&amp;amp;vec![...]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is useless because the reference operator &lt;code&gt;&amp;amp;&lt;/code&gt; implies that I don't need ownership of this vector. And If I don't need ownership, there's no need to use a vector at all! It's a waste of resources. Instead, I should use a slice: &lt;code&gt;&amp;amp;[...]&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ⭐🗺️ Starchart
&lt;/h2&gt;

&lt;p&gt;This week's work on Starchart is a mix of housekeeping and research.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Dependencies (&lt;a href="https://github.com/DevelopingSpace/starchart/pull/870" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;It's only been two weeks since my last "update dependencies" PR, but we were swarmed by another wave. This time, I upgraded 18 packages without any breakages.&lt;/p&gt;

&lt;p&gt;I was stumbled by a failing test cause by dependabot, but quickly figured out the problem: All &lt;code&gt;remix&lt;/code&gt; packages need to be updated together, but dependabot tried to update just one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Looking into MX Records
&lt;/h3&gt;

&lt;p&gt;This one was tricky because the dev server is not deployed anywhere and it's hard to test public-facing services like DNS on a mock server.&lt;/p&gt;

&lt;p&gt;With the help of AI (or rather, LLM 👀), I was recommended the &lt;code&gt;aws&lt;/code&gt; client, and it worked!&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/DevelopingSpace/starchart/pull/852#issuecomment-2734976067" 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;
        Comment for
      &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; commented on &lt;a href="https://github.com/DevelopingSpace/starchart/pull/852#issuecomment-2734976067" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 18, 2025&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;@lilyhuang-github &lt;a class="mentioned-user" href="https://dev.to/uday-rana"&gt;@uday-rana&lt;/a&gt; I was able to use the aws client to retrieve the DNS records from the &lt;code&gt;motoserver/moto&lt;/code&gt; mock server:&lt;/p&gt;
&lt;p&gt;Using this command:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell js-code-highlight"&gt;
&lt;pre&gt;aws route53 list-resource-record-sets --hosted-zone-id &lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt;zone-id&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; --endpoint-url=&lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt;url&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;I got:&lt;/p&gt;
&lt;div class="highlight highlight-source-json js-code-highlight"&gt;
&lt;pre&gt;        {
            &lt;span class="pl-ent"&gt;"Name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;mail.user1.starchart.com.&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
            &lt;span class="pl-ent"&gt;"Type"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;MX&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
            &lt;span class="pl-ent"&gt;"TTL"&lt;/span&gt;: &lt;span class="pl-c1"&gt;300&lt;/span&gt;,
            &lt;span class="pl-ent"&gt;"ResourceRecords"&lt;/span&gt;: [
                {
                    &lt;span class="pl-ent"&gt;"Value"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;10 mail.com&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
                }
            ]
        }&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Seems like the record is successfully created!&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/852#issuecomment-2734976067" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I did so by pulling up a shell inside the mock server's docker container and installing the &lt;code&gt;aws&lt;/code&gt; client in there. Before you tell me this is super illegal, and I can just install the client on my native system, I did it this way because the client comes with a ton of dependencies and I don't really want to mess up my own system because of it. 😆&lt;/p&gt;

&lt;h3&gt;
  
  
  Investigating the &lt;code&gt;samlify&lt;/code&gt; Breakage
&lt;/h3&gt;

&lt;p&gt;This package has been broken since version &lt;code&gt;2.8.11&lt;/code&gt; and we're on version &lt;code&gt;2.8.10&lt;/code&gt; for now.&lt;/p&gt;

&lt;p&gt;I decided upgrade this again and analyze the error message. Here's what I had on the server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Backtrace:
1 www/_include.php:45 (SimpleSAML_exception_handler)
0 [builtin] (N/A)
Caused by: Exception: Invalid value of boolean attribute 'AllowCreate': ''
Backtrace:
6 vendor/simplesamlphp/saml2/src/SAML2/Utils.php:282 (SAML2\Utils::parseBoolean)
5 vendor/simplesamlphp/saml2/src/SAML2/AuthnRequest.php:233 (SAML2\AuthnRequest::parseNameIdPolicy)
4 vendor/simplesamlphp/saml2/src/SAML2/AuthnRequest.php:168 (SAML2\AuthnRequest::__construct)
3 vendor/simplesamlphp/saml2/src/SAML2/Message.php:572 (SAML2\Message::fromXML)
2 vendor/simplesamlphp/saml2/src/SAML2/HTTPRedirect.php:125 (SAML2\HTTPRedirect::receive)
1 modules/saml/lib/IdP/SAML2.php:316 (sspmod_saml_IdP_SAML2::receiveAuthnRequest)
0 www/saml2/idp/SSOService.php:19 (N/A)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although the error itself is not related to our project, the &lt;code&gt;AllowCreate&lt;/code&gt; attribute caught my eye. I first searched for it within our code base. I found nothing there, so I decided to look upstream.&lt;/p&gt;

&lt;p&gt;A quick search in &lt;code&gt;samlify&lt;/code&gt;'s repo brought me to &lt;a href="https://github.com/tngan/samlify/issues/538" rel="noopener noreferrer"&gt;this issue&lt;/a&gt;, and it seems like many people are experiencing this issue as well. Luckily, &lt;a href="https://github.com/tngan/samlify/pull/561" rel="noopener noreferrer"&gt;a fix&lt;/a&gt; is already on its way.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❤️🧠 A Quick Note on Stress
&lt;/h2&gt;

&lt;p&gt;The past few weeks have been really difficult to navigate. Tasks from school are piling up, and the stress from job searching too. I was worried that I couldn't get much else done in the midst of all that. I guess this blog proved that wrong and I'm proud of it haha. Let's hope that I can keep this momentum forward!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
      <category>rust</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Sprint 4 - TLS Certificates and CSP</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Thu, 13 Mar 2025 14:23:42 +0000</pubDate>
      <link>https://dev.to/theoforger/sprint-4-tls-certificates-and-csp-5cd4</link>
      <guid>https://dev.to/theoforger/sprint-4-tls-certificates-and-csp-5cd4</guid>
      <description>&lt;p&gt;Another week of research! This week my focus has been on stagnant issues from the past. I even discovered some new bugs during the process.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  React hydration errors (&lt;a href="https://github.com/DevelopingSpace/starchart/issues/845" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;This was a happy accident. A while ago I was looking into how to secure my home server, and came across &lt;a href="https://developer.mozilla.org/en-US/observatory" rel="noopener noreferrer"&gt;HTTP Observatory&lt;/a&gt; by Mozilla. It's a service that scans the HTTP headers of your website and gives you feedback on security practices.&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%2Fyu7qqfvumodk0wdj9ip4.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%2Fyu7qqfvumodk0wdj9ip4.png" alt="HTTP Observatory" width="800" height="780"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, among other things, I learned about &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy" rel="noopener noreferrer"&gt;Content Secure Policy&lt;/a&gt; or CSP for short. It's an HTTP header that dictates where the website is allow to retrieve each type of content, like scripts, images, stylesheets, etc.&lt;/p&gt;

&lt;p&gt;This issue on Starchart was posted by &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;Uday&lt;/a&gt; last week. But when I looked at the screenshots, I saw some very familiar errors in the console:&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%2Fh581az8duxwo05ot5hwv.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%2Fh581az8duxwo05ot5hwv.png" alt="CSP error" width="800" height="61"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A good security practice with CSP is to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP#nonces" rel="noopener noreferrer"&gt;restrict the loading of scripts to only 'self' or an nonce value&lt;/a&gt;, which is exactly how it's configured here.&lt;/p&gt;

&lt;p&gt;I suspect that maybe some code related to styling isn't very stable and get the &lt;code&gt;nonce&lt;/code&gt; value wrong. Of course, more investigation is still needed, but it's a good start!&lt;/p&gt;

&lt;h3&gt;
  
  
  Investigate Let's Encrypt certificate chain change (&lt;a href="https://github.com/DevelopingSpace/starchart/issues/766" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;I've been wanting to look into this one for a while. The TLS protocol is always something that fascinates me and I've been learning it in my own time, both for my home server and for personal interest.&lt;/p&gt;

&lt;p&gt;The issue here is related to TLS certificates. The Starchart project requests certificates from &lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;Let's Encrypt&lt;/a&gt;, and last year there was a change in their chain of trust. So we want to know what impact it had to our project.&lt;/p&gt;

&lt;p&gt;After spending some time renewing my knowledge of TLS, I looked into &lt;a href="https://letsencrypt.org/2023/07/10/cross-sign-expiration/" rel="noopener noreferrer"&gt;the official blog from Let's Encrypt&lt;/a&gt; There they outlined a few situations where this could be a problem:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Never downloading the chain at all and only serving the end-entity certificate&lt;/li&gt;
&lt;li&gt;Never downloading the chain and instead serving a hard-coded chain&lt;/li&gt;
&lt;li&gt;Only downloading the chain at first issuance and not re-downloading during renewals. Please ensure that your client does not fall into any of these buckets.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Looking into out code, we always get the full chain from Let's Encrypt and then split it into an end entity certificate and an intermediate chain:&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;// fullChain is the public certificate + the intermediate certificate(s) for Let's Encrypt&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fullChain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCertificate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// certificate is the public certificate, chain is the intermediate certificate(s) for Let's Encrypt&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;chainArray&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;acme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitPemChain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fullChain&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;chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chainArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&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;It seems like we are able to mitigate the issue on the server side. However, if someone is still using the old certificates, they would not continue to work. But I don't think there's much we can do here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incorrect content in downloaded certificates (&lt;a href="https://github.com/DevelopingSpace/starchart/issues/856" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;I noticed this during my research the previous one: The download buttons on the certificate managements page give you the wrong certificates. It's a problem in the development build as well as the already deployed production build! I'm genuinely surprised it has gone unnoticed for as long as it has!&lt;/p&gt;

&lt;p&gt;To be more specific, there seems to be something wrong with how the website handles intermediate chain for downloads. Although everything shows up under the hidden section just fine, the file always excludes the intermediate CA certificates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hurl
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New Issue (&lt;a href="https://github.com/Orange-OpenSource/hurl/issues/922" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;This week I haven't been focusing on Hurl that much, but I had my name assigned on this new issue. Here I'll be working on a new query which returns the specs of HTTP redirections.&lt;/p&gt;

&lt;p&gt;Similar to my IP address query feature, you should be able to use these specs in &lt;code&gt;Asserts&lt;/code&gt; and &lt;code&gt;Capture&lt;/code&gt;. Since there can be multiple redirects for one request, there's a new challenge to handle multiple query results in a list.&lt;/p&gt;

&lt;h3&gt;
  
  
  New Release!
&lt;/h3&gt;

&lt;p&gt;Earlier today they made a new release of Hurl &lt;a href="https://github.com/Orange-OpenSource/hurl/releases/tag/6.1.0" rel="noopener noreferrer"&gt;v6.1.0&lt;/a&gt;. This release contains everything I've worked on since last year! Now everyone can finally use those features (and think of me while they do 😂)! Here's the &lt;a href="https://hurl.dev/blog/2025/03/14/announcing-hurl-6.1.0.html" rel="noopener noreferrer"&gt;official blog&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%2Fus04ht0btd5056104vf0.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%2Fus04ht0btd5056104vf0.png" alt="Hurl release v6.1.0" width="800" height="628"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Sprint 3 - Hello DNS My Old Friend</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Thu, 06 Mar 2025 15:28:08 +0000</pubDate>
      <link>https://dev.to/theoforger/sprint-3-hello-dns-my-old-friend-51nn</link>
      <guid>https://dev.to/theoforger/sprint-3-hello-dns-my-old-friend-51nn</guid>
      <description>&lt;p&gt;After a short break, it's time to get back to the second half of this sprint. This time, I worked on a new feature and some maintenance for Starchart, as well as more followup work for Hurl.&lt;/p&gt;

&lt;h2&gt;
  
  
  🌐🦀 Hurl
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Integration Tests and Docs (&lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3815" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;As a followup of the previous PRs, this one finally concludes the &lt;code&gt;ip&lt;/code&gt; query feature! As I'm getting more familiar with this project, I now know exactly where to look when it comes to docs and integration tests.&lt;/p&gt;

&lt;p&gt;However, some tests are still failing due to "patternization": The integration test system checks the output and compares it with an expected value. However, some output information is run time specific. For example, performance metrics and timing information is different for each run. So the output for these data should be patternized:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
Original
&lt;/th&gt;
&lt;th&gt;
Patternized
&lt;/th&gt;
&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;
&lt;pre&gt;
"timings":{
  "app_connect":0,
  "begin_call":"2025-03-05T22:38:53.547654Z",
  "connect":207,
  "end_call":"2025-03-05T22:38:53.563185Z",
  "name_lookup":34,
  "pre_transfer":248,
  "start_transfer":15444,
  "total":15468
}
&lt;/pre&gt;
&lt;/td&gt;

&lt;td&gt;
&lt;pre&gt;
"timings":{
  "app_connect":"&amp;lt;&amp;lt;&amp;lt;\\d+&amp;gt;&amp;gt;&amp;gt;",
  "begin_call":"&amp;lt;&amp;lt;&amp;lt;.*?&amp;gt;&amp;gt;&amp;gt;",
  "connect":"&amp;lt;&amp;lt;&amp;lt;\\d+&amp;gt;&amp;gt;&amp;gt;",
  "end_call":"&amp;lt;&amp;lt;&amp;lt;.*?&amp;gt;&amp;gt;&amp;gt;",
  "name_lookup":"&amp;lt;&amp;lt;&amp;lt;\\d+&amp;gt;&amp;gt;&amp;gt;",
  "pre_transfer":"&amp;lt;&amp;lt;&amp;lt;\\d+&amp;gt;&amp;gt;&amp;gt;",
  "start_transfer":"&amp;lt;&amp;lt;&amp;lt;\\d+&amp;gt;&amp;gt;&amp;gt;",
  "total":"&amp;lt;&amp;lt;&amp;lt;\\d+&amp;gt;&amp;gt;&amp;gt;"
}
&lt;/pre&gt;
&lt;/td&gt;

&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;However, &lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3815#pullrequestreview-2662686672" rel="noopener noreferrer"&gt;according to the maintainer&lt;/a&gt;, there doesn't seem to be a way to automate this. So fixing it would be manual labor, which is not the end of the world since they don't have many tests like this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Good News!
&lt;/h3&gt;

&lt;p&gt;In a previous blog I shared my concern that the Hurl project might take a break from contributions. Ho I'm happy to inform that &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3106#issuecomment-2672708570" rel="noopener noreferrer"&gt;they made an exception for me&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Of course, I totally understand why they made that decision in the first place: There is huge influx of contributions, a planned release, and considering how much care and patience they put into each contribution, it's a lot of work! I'm flattered by this exception made by them, but at the same time, it's reassuring and inspiring to see my work being recognized.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⭐🗺️ Starchart
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Update Dependencies (&lt;a href="https://github.com/DevelopingSpace/starchart/pull/844" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Of course, it can't be another week on Starchart without some good old dependency updates. This time I really tried to eliminate as many of them as I could:&lt;/p&gt;

&lt;p&gt;I knew upgrading to React 19 was going to be painful, since it introduced a ton of &lt;a href="https://react.dev/blog/2024/04/25/react-19-upgrade-guide" rel="noopener noreferrer"&gt;breaking changes&lt;/a&gt;. However, as I always do with upgrades like this, I tried to upgrade it anyway and see if anything would break. To my surprise, when I tested it locally, other than one small &lt;a href="https://react.dev/blog/2024/04/25/react-19-upgrade-guide#the-jsx-namespace-in-typescript" rel="noopener noreferrer"&gt;issue regarding the JSX namespace&lt;/a&gt;, it just worked!&lt;/p&gt;

&lt;p&gt;However, when I filed the PR, I was welcomed with a failed e2e test. Turned out some code is broken in mobile safari browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  3 failed
    [Mobile Safari] › test/e2e/certificate-available.spec.ts:66:7 › Certificate Page › Download Certificate 
    [Mobile Safari] › test/e2e/header/header.spec.ts:11:7 › sign out of the account › sign out ─────
    [Mobile Safari] › test/e2e/landing-page.spec.ts:25:7 › Landing Page › DNS Records Instructions Link 
  1 flaky
    [Mobile Chrome] › test/e2e/landing-page.spec.ts:25:7 › Landing Page › DNS Records Instructions Link 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Truly an "it work on my machine" moment 😂.&lt;/p&gt;

&lt;p&gt;In addition, I attempted to upgrade &lt;code&gt;express&lt;/code&gt; to v5. I did notice that version 5 was marked with the "next" tag, but my inner "Arch Linux spirit" was telling me to update anyway! Turned out it wasn't the best decision I've made, as others &lt;a href="https://github.com/DevelopingSpace/starchart/pull/844#discussion_r1982671789" rel="noopener noreferrer"&gt;prefer to stay at v4 for now&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%2Fyt9aukduevmte55wrwov.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%2Fyt9aukduevmte55wrwov.png" alt="express v5 marked as next" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  MX Records (&lt;a href="https://github.com/DevelopingSpace/starchart/pull/852" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;This was the major feature of this sprint! As we frustratingly navigated through various dependency updates and eventually realized that it's a never ending ride, I decided to finally start working on this &lt;a href="https://github.com/DevelopingSpace/starchart/issues/787" rel="noopener noreferrer"&gt;feature request to support DNS MX records&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Like I said in the title, I had a complicated relationship with DNS. As someone who's battled with internet censorship for many years, DNS has always been the number one pain point no matter which proxy tool I choose. However, at the same time, I can't help but admire the simplicity of it and the critical rule it plays in modern internet infrastructure. &lt;/p&gt;

&lt;p&gt;Even though I also had experience managing DNS records for my home server, I've never dealt with MX records before. Research time!&lt;/p&gt;

&lt;p&gt;I came across this &lt;a href="https://www.cloudflare.com/learning/dns/dns-records/dns-mx-record/" rel="noopener noreferrer"&gt;short article from Cloudflare&lt;/a&gt; which explained it well. Like many other common DNS records, there isn't much complexity to it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;example.com&lt;/th&gt;
&lt;th&gt;record type&lt;/th&gt;
&lt;th&gt;priority&lt;/th&gt;
&lt;th&gt;value&lt;/th&gt;
&lt;th&gt;TTL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;@&lt;/td&gt;
&lt;td&gt;MX&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;mailhost1.example.com&lt;/td&gt;
&lt;td&gt;45000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In this example, the record essentially says:&lt;/p&gt;

&lt;p&gt;Any email destined for the root domain &lt;code&gt;example.com&lt;/code&gt; should be delivered to the mail server at &lt;code&gt;mailhost1.example.com&lt;/code&gt;. In case this record fails to resolve, look for other records with priority higher than 10. And this record will come into effect in 45000 seconds.&lt;/p&gt;

&lt;p&gt;The implementation wasn't too hard either. I modified the &lt;code&gt;prisma&lt;/code&gt; schema file to include the &lt;code&gt;MX&lt;/code&gt; record type:&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="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;DnsRecordType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;A&lt;/span&gt;
  &lt;span class="nx"&gt;AAAA&lt;/span&gt;
  &lt;span class="nx"&gt;CNAME&lt;/span&gt;
  &lt;span class="nx"&gt;MX&lt;/span&gt;
  &lt;span class="nx"&gt;TXT&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And made sure the value includes a priority &lt;a href="https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html#MXFormat" rel="noopener noreferrer"&gt;as stated in the documentation&lt;/a&gt; (I decided to use 10 as the default since priority is irrelevant in this project):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;DnsRecordType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MX&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10 &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&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;Now, the only problem is that, while the unit tests and integration tests can both past, since DNS is pratically a public service and in this case also involves a mail server, I couldn't figure out a way to test if it's actually functional. I already opened a draft PR. Let's hope we can find a solution together!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Sprint 3 - Dependencies Galore</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Thu, 20 Feb 2025 15:03:56 +0000</pubDate>
      <link>https://dev.to/theoforger/sprint-3-dependencies-galore-2e1k</link>
      <guid>https://dev.to/theoforger/sprint-3-dependencies-galore-2e1k</guid>
      <description>&lt;p&gt;In this sprint, I shifted my focus from Hurl to Starchart. Spoiler alert: Lots of dependencies were involved 👀.&lt;/p&gt;

&lt;h2&gt;
  
  
  🦀 Hurl
&lt;/h2&gt;

&lt;p&gt;I didn’t make much progress on Hurl this week. However, I did finish the requested changes for &lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3715" rel="noopener noreferrer"&gt;my previous PR&lt;/a&gt;, which involved adjusting some error handling rules. It wasn’t anything groundbreaking, but I did learn a few new tricks from &lt;code&gt;clippy&lt;/code&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%2Fhbewh144smqatlrbv7zx.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%2Fhbewh144smqatlrbv7zx.png" alt="Clippy giving useful advice" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I encountered the errors above after applying a suggestion from the maintainer:&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;is_ipv4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;IpAddr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&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;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="nf"&gt;.is_ipv4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal was to ensure &lt;code&gt;is_ipv4&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt; only if the parse result is &lt;code&gt;OK()&lt;/code&gt; and the parsed IP address is IPv4. Since we’re dealing with booleans here, &lt;code&gt;clippy&lt;/code&gt; suggested using &lt;code&gt;.is_ok_and&lt;/code&gt;:&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;is_ipv4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;IpAddr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.is_ok_and&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="nf"&gt;.is_ipv4&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This accomplishes the same result but makes the code much more readable!&lt;/p&gt;

&lt;h3&gt;
  
  
  Concern for the Future
&lt;/h3&gt;

&lt;p&gt;I saw a comment from the Hurl maintainer that they are pausing contributor pull requests. Since Hurl is my 80% project, I’m wondering what this means. Should I focus more on Starchart, or perhaps look for something else for the time being?&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Code Reviews
&lt;/h3&gt;

&lt;p&gt;It was more difficult than I expected—not in terms of technicality, but because I’m still unfamiliar with reviewing code in a new project. I tried to stick to &lt;a href="https://google.github.io/eng-practices/review/" rel="noopener noreferrer"&gt;this guide&lt;/a&gt; that was shared with us last semester.&lt;/p&gt;

&lt;h4&gt;
  
  
  Update Remix to v2 &lt;a href="https://github.com/DevelopingSpace/starchart/pull/833" rel="noopener noreferrer"&gt;#833&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;At first, I was completely lost. There were random changes all over the place. But by reviewing the commits one at a time, I realized that most of the changes came from a migration tool. I compared them with the PR description, and everything seemed to be in order.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bump Prisma to 4.16.2 to match @prisma/client &lt;a href="https://github.com/DevelopingSpace/starchart/pull/831" rel="noopener noreferrer"&gt;#831&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;It was a simple version bump. However, during the review, I went to Prisma's &lt;a href="https://www.prisma.io/docs/orm/tools/prisma-cli#installation" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; and found that the cli tool should be installed as a development dependency, which was a helpful discovery.&lt;/p&gt;

&lt;h4&gt;
  
  
  Add ESLint 9 to support oxlint &lt;a href="https://github.com/DevelopingSpace/starchart/pull/834" rel="noopener noreferrer"&gt;#834&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Since I worked on the same code previously to &lt;a href="https://github.com/DevelopingSpace/starchart/pull/788" rel="noopener noreferrer"&gt;remove ESLint&lt;/a&gt;, it wasn’t too challenging. However, this PR added even more ignore configs than what we already had. So, I asked the author if there was a way to consolidate them into a single source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Dependencies - Part 1 (&lt;a href="https://github.com/DevelopingSpace/starchart/pull/839" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;In this PR, I used &lt;a href="https://google.github.io/eng-practices/review/" rel="noopener noreferrer"&gt;&lt;code&gt;npm-check-updates&lt;/code&gt;&lt;/a&gt; to update packages with minor version bumps. Expecting no breaking changes, I upgraded everything at once. Of course, it broke 😆. The issue was I couldn’t pinpoint which package caused the problem.&lt;/p&gt;

&lt;p&gt;I reverted my changes and applied the updates one by one. Eventually, I discovered that the culprit was &lt;a href="https://www.npmjs.com/package/samlify" rel="noopener noreferrer"&gt;&lt;code&gt;samlify&lt;/code&gt;&lt;/a&gt;. It was surprising, considering it was just a minor version bump from &lt;code&gt;2.8.10&lt;/code&gt; to &lt;code&gt;2.8.11&lt;/code&gt;. I checked the changelog but couldn’t find any relevant information, so I decided to exclude it from this PR.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Dependencies - Part 2 (&lt;a href="https://github.com/DevelopingSpace/starchart/pull/840" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Learning from my previous mistake, I upgraded one package at a time in this round. Since I was dealing with major version updates, I made sure to check the changelog beforehand.&lt;/p&gt;

&lt;p&gt;I encountered only two breaking changes: For &lt;code&gt;husky&lt;/code&gt;, I found a &lt;a href="https://github.com/typicode/husky/releases/tag/v9.0.1" rel="noopener noreferrer"&gt;migration guide&lt;/a&gt; in the release notes. For &lt;code&gt;isbot&lt;/code&gt;, they also &lt;a href="https://github.com/omrilotan/isbot/blob/main/CHANGELOG.md#400" rel="noopener noreferrer"&gt;outlined&lt;/a&gt; the breaking changes. Both were simple syntax adjustments, nothing too complex.&lt;/p&gt;

&lt;p&gt;I also got stuck with &lt;a href="https://www.npmjs.com/package/prisma" rel="noopener noreferrer"&gt;&lt;code&gt;prisma&lt;/code&gt;&lt;/a&gt;. Every time I updated it, the project would break and throw errors. Some quick research revealed that I needed to run &lt;code&gt;prisma generate&lt;/code&gt; each time I changed versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;After the two rounds of updates, the list of outdated packages looked much cleaner:&lt;/p&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;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%2Fmt9omavipsd0qtxwovmy.png" alt="before" width="708" height="1156"&gt;&lt;/td&gt;
&lt;td&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%2Fgzyxh4w2fq3tzs1c03rd.png" alt="after" width="708" height="468"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As for the breaking packages, I created &lt;a href="https://github.com/DevelopingSpace/starchart/issues/841" rel="noopener noreferrer"&gt;an issue&lt;/a&gt; to track them.&lt;/p&gt;

&lt;h3&gt;
  
  
  🤔 Some Thoughts on Dependencies
&lt;/h3&gt;

&lt;p&gt;I had a chat with &lt;a href="https://github.com/uday-rana" rel="noopener noreferrer"&gt;Uday&lt;/a&gt; recently, and he voiced a concern that we’re spending too much time on dependency updates.&lt;/p&gt;

&lt;p&gt;And he’s right. We’ve been going back and forth on dependencies for quite a while now: discussing whether we should maintain certain dependencies out of frustration, dealing with dependencies that randomly break things with unclear changelog documentation, and handling unmerged dependency updates that block further updates or new features...&lt;/p&gt;

&lt;p&gt;Does managing dependencies really take this much time? Is it just because we were assigned to an outdated project? Is there a better way to handle dependencies so we don’t have to fight with them so much?&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Sprint 2 - Picking Up the Pace</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Thu, 13 Feb 2025 15:37:18 +0000</pubDate>
      <link>https://dev.to/theoforger/sprint-2-picking-up-the-pace-420a</link>
      <guid>https://dev.to/theoforger/sprint-2-picking-up-the-pace-420a</guid>
      <description>&lt;p&gt;This is the end of Sprint 2. This Sprint has gotten me into a lot of joy and pain, and let me tell you all about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  🪄 Hurl
&lt;/h2&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3106" 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 ip query for getting resolved response IP
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#3106&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/3106" rel="noopener noreferrer"&gt;&lt;time&gt;Aug 01, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;A proposal to add an &lt;code&gt;ip&lt;/code&gt; query&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET https://foo.com
HTTP 200
[Asserts]
ip == "192.168.0.1"
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;GET https://foo.com
HTTP 200
[Asserts]
ip matches /2001:0000:130F:0000:0000:09C0:876A:\d*/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;libcurl&lt;/code&gt; the corresponding call is &lt;a href="https://curl.se/libcurl/c/CURLINFO_PRIMARY_IP.html" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;CURLINFO_PRIMARY_IP&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is also a &lt;a href="https://curl.se/libcurl/c/CURLINFO_LOCAL_IP.html" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;CURLINFO_LOCAL_IP&lt;/code&gt;&lt;/a&gt; but I've the impression that user expectation is more on primary ip.&lt;/p&gt;
&lt;p&gt;Question: what's about port ? Does the query &lt;code&gt;ip&lt;/code&gt; exctract the IP address and the port (&lt;code&gt;192.168.0.01:8080&lt;/code&gt;), or do we have a separate &lt;code&gt;port&lt;/code&gt; query that we can do latter?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET https://foo.com
HTTP 200
[Asserts]
ip == "192.168.0.1"
port == 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code&gt;ip&lt;/code&gt;/&lt;code&gt;port&lt;/code&gt;as separated queries, we can also have &lt;code&gt;isIPv6&lt;/code&gt; and &lt;code&gt;isIPv4&lt;/code&gt; predicates:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET https://foo.com
HTTP 200
[Asserts]
ip isIPv6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Idea from &lt;a class="mentioned-user" href="https://dev.to/lepapareil"&gt;@lepapareil&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/Orange-OpenSource/hurl/issues/3106" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
This week I've been working to implement this feature to enable hurl users to assert on IP addresses for each request. Since there were quite a few things to do, I decided to break it into multiple PRs.
&lt;h3&gt;
  
  
  Add ip address to http::Response (&lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3695" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;This was a continuation from last week's research. To make the asserts work, first I had to capture that from libcurl and include it in Hurl's &lt;code&gt;Response&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;To achieve that, I used the method &lt;a href="https://docs.rs/curl/latest/curl/easy/struct.Easy2.html#method.primary_ip" rel="noopener noreferrer"&gt;&lt;code&gt;primary_ip&lt;/code&gt;&lt;/a&gt; provided by the &lt;code&gt;curl&lt;/code&gt; crate. There was some issues regarding the return type of this method and the implementation of type conversions, but we worked it out &lt;a href="https://dev.to/theoforger/sprint-2-getting-stuck-a-little-4pfh"&gt;during the previous Sprint&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Other than that, nothing much happened in this PR. There was some changes regarding names and documentation, but it was merged quickly after.&lt;/p&gt;
&lt;h3&gt;
  
  
  Allow assert on ip address (&lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3705" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;After last week's discussion, we decided to simply use the &lt;code&gt;string&lt;/code&gt; type to handle ip address queries in the Hurl file. At that point I didn't really understand much of the code, but I was able to find a similar query option : &lt;code&gt;url&lt;/code&gt;. Imitating the code, I was able to create a new query entry.&lt;/p&gt;

&lt;p&gt;For example:&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="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;url_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ParseResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;QueryValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;try_literal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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="nn"&gt;QueryValue&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Url&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;became:&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="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;ip_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ParseResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;QueryValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;try_literal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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="nn"&gt;QueryValue&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Ip&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;To my surprise, when I tested it afterwards, everything worked! &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;matches&lt;/code&gt; or &lt;code&gt;contains&lt;/code&gt;... All the keywords was properly working. Turned out Hurl already had the code to handle all string typed queries generically, so all I had to do was creating the query and plugging it right in. Super cool!&lt;/p&gt;

&lt;h3&gt;
  
  
  Allow asserts on ip versions (&lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3715" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;This was technically a different feature but it was still a part of the original issue. In this PR, instead of treating the IP address as a string and query on the text content, I had to figure out way to evaluate the IP version.&lt;/p&gt;

&lt;p&gt;The maintainer suggested to simply take the IP query strings and convert them to &lt;code&gt;std::net::IpAddr&lt;/code&gt;. Since this is an enum built-in with the &lt;code&gt;V4&lt;/code&gt; and &lt;code&gt;V6&lt;/code&gt; variants, if the conversion succeeds, I could match the pattern to get the IP version.&lt;/p&gt;

&lt;p&gt;However, this task was not nearly as straightforward as the last PR. Since I didn't fully understand the code, I had a very difficult time locating where I even implement this conversion.&lt;/p&gt;

&lt;p&gt;First I was determined to figure this out myself. I sat down and carefully read the code, I drafted a few diagrams to help me understand the workflow. However, in Hurl's file parser, whenever I tried to print something, or use the debugger to display something, I would get a strange-looking structure instead of actual text like so:&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%2Fikgh0lhrscf2orlf6a6v.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%2Fikgh0lhrscf2orlf6a6v.png" alt="Hurl AST" width="722" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was beyond confused. I had to ask the maintainer about this. Turned out they were using something called an AST (abstract syntax tree). This structure maps the relative locations of each section of the file without actually parsing them. You can &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3106#issuecomment-2643250787" rel="noopener noreferrer"&gt;read more&lt;/a&gt; in the maintainer's comment.&lt;/p&gt;

&lt;p&gt;With that knowledge in mind and a bit more research, I finally was able to implement this feature. Now I'm still going back and forth with the maintainer regarding error handling, but I'm sure this feature will land soon!&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Update @aws-sdk/client-route-53 (&lt;a href="https://github.com/DevelopingSpace/starchart/pull/830" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;I was looking at Starchart yesterday and saw a list of pull requests opened by &lt;code&gt;dependabot&lt;/code&gt;, one of which had a failed CI check. I decided to look in a little further. This &lt;a href="https://github.com/DevelopingSpace/starchart/pull/829" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; attempted to update the package &lt;code&gt;@aws-sdk/client-route-53&lt;/code&gt; from 3.360.0 to 3.744.0. That's quite a bit gap in version numbers.&lt;/p&gt;

&lt;p&gt;The CI pipeline failed because of a type mismatch. I started by checking &lt;a href="https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-route-53/CHANGELOG.md" rel="noopener noreferrer"&gt;the changelog&lt;/a&gt; but I didn't notice any changes regarding types.&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%2Fnjtsv0k067d8i5upp9eg.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%2Fnjtsv0k067d8i5upp9eg.png" alt="changelog meme" width="800" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fortunately, my IDE was able to help me with locate two new types introduced in the new version:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;
RRType
&lt;/th&gt;
&lt;th&gt;
ChangeAction
&lt;/th&gt;
&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;
&lt;pre&gt;
/**
 * &lt;a class="mentioned-user" href="https://dev.to/public"&gt;@public&lt;/a&gt;
 * @enum
 */
export declare const RRType: {
    readonly A: "A";
    readonly AAAA: "AAAA";
    readonly CAA: "CAA";
    readonly CNAME: "CNAME";
    readonly DS: "DS";
    readonly HTTPS: "HTTPS";
    readonly MX: "MX";
    readonly NAPTR: "NAPTR";
    readonly NS: "NS";
    readonly PTR: "PTR";
    readonly SOA: "SOA";
    readonly SPF: "SPF";
    readonly SRV: "SRV";
    readonly SSHFP: "SSHFP";
    readonly SVCB: "SVCB";
    readonly TLSA: "TLSA";
    readonly TXT: "TXT";
};
/**
 * &lt;a class="mentioned-user" href="https://dev.to/public"&gt;@public&lt;/a&gt;
 */
export type RRType = (typeof RRType)[keyof typeof RRType];
&lt;/pre&gt;
&lt;/td&gt;

&lt;td&gt;
&lt;pre&gt;

/**
 * &lt;a class="mentioned-user" href="https://dev.to/public"&gt;@public&lt;/a&gt;
 * @enum
 */
export declare const ChangeAction: {
    readonly CREATE: "CREATE";
    readonly DELETE: "DELETE";
    readonly UPSERT: "UPSERT";
};
/**
 * &lt;a class="mentioned-user" href="https://dev.to/public"&gt;@public&lt;/a&gt;
 */
export type ChangeAction = (typeof ChangeAction)[keyof typeof ChangeAction];

&lt;/pre&gt;
&lt;/td&gt;

&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This part of the code is responsible for managing DNS records. &lt;code&gt;RRType&lt;/code&gt; defines the type of DNS record and &lt;code&gt;ChangeAction&lt;/code&gt; defines the type of changes to perform on an existing record. While all these types were previously represented by &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I changed the code to the new types and filed a PR. Later the review came back, suggesting that I create a utility function to handle the type conversion. And this is where I'm at right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  📝 Conclusion and What's Next
&lt;/h2&gt;

&lt;p&gt;This Sprint felt much more eventful than the last one. In the Hurl project, I was working on a different area of code, which means that more time were spent on search and asking questions. I also made more mistakes because of this unfamiliarity. On the Starchart's side, although I haven't taken much action yet, I suspect there to be more to come:&lt;/p&gt;

&lt;p&gt;For the next Sprint, I might need to dial back a little on the Hurl project, since the maintainer mentioned that they have &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/2199#issuecomment-2646410667" rel="noopener noreferrer"&gt;stopped taking in new features&lt;/a&gt; until the next release (&lt;code&gt;6.1.0&lt;/code&gt;). So my plan is to pick a few bugs to investigate there, while shifting my focus a little more to Starchart.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
      <category>rust</category>
    </item>
    <item>
      <title>Sprint 2 - Getting Stuck A Little</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Thu, 06 Feb 2025 13:52:29 +0000</pubDate>
      <link>https://dev.to/theoforger/sprint-2-getting-stuck-a-little-4pfh</link>
      <guid>https://dev.to/theoforger/sprint-2-getting-stuck-a-little-4pfh</guid>
      <description>&lt;p&gt;This week I've mostly been working on this issue from Hurl. It proposes a new feature which allows users to query the IP address of the response and assert on it.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3106" 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 ip query for getting resolved response IP
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#3106&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/3106" rel="noopener noreferrer"&gt;&lt;time&gt;Aug 01, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;A proposal to add an &lt;code&gt;ip&lt;/code&gt; query&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GET https://foo.com
HTTP 200
[Asserts]
ip == "192.168.0.1"
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;GET https://foo.com
HTTP 200
[Asserts]
ip matches /2001:0000:130F:0000:0000:09C0:876A:\d*/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In &lt;code&gt;libcurl&lt;/code&gt; the corresponding call is &lt;a href="https://curl.se/libcurl/c/CURLINFO_PRIMARY_IP.html" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;CURLINFO_PRIMARY_IP&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is also a &lt;a href="https://curl.se/libcurl/c/CURLINFO_LOCAL_IP.html" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;CURLINFO_LOCAL_IP&lt;/code&gt;&lt;/a&gt; but I've the impression that user expectation is more on primary ip.&lt;/p&gt;

&lt;p&gt;Question: what's about port ? Does the query &lt;code&gt;ip&lt;/code&gt; exctract the IP address and the port (&lt;code&gt;192.168.0.01:8080&lt;/code&gt;), or do we have a separate &lt;code&gt;port&lt;/code&gt; query that we can do latter?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GET https://foo.com
HTTP 200
[Asserts]
ip == "192.168.0.1"
port == 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With &lt;code&gt;ip&lt;/code&gt;/&lt;code&gt;port&lt;/code&gt;as separated queries, we can also have &lt;code&gt;isIPv6&lt;/code&gt; and &lt;code&gt;isIPv4&lt;/code&gt; predicates:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GET https://foo.com
HTTP 200
[Asserts]
ip isIPv6
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Idea from &lt;a class="mentioned-user" href="https://dev.to/lepapareil"&gt;@lepapareil&lt;/a&gt; 😎&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;/div&amp;gt;
&amp;lt;div class="gh-btn-container"&amp;gt;&amp;lt;a class="gh-btn" href="https://github.com/Orange-OpenSource/hurl/issues/3106"&amp;gt;View on GitHub&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
 

&lt;p&gt;I decided to really break it down into smaller PRs since there's going to be quite a lot of work to do.&lt;/p&gt;

&lt;p&gt;As expected, since I'm moving into a new territory of the project, this would be a bumpy start. Luckily the maintainer gave me &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3106#issuecomment-2622608077" rel="noopener noreferrer"&gt;some guidance&lt;/a&gt; to work with.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔧 Modify the &lt;code&gt;Response&lt;/code&gt; Module (&lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3106" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;The first step was to modify the &lt;code&gt;Response&lt;/code&gt; module. This was surprisingly easy: I added an &lt;code&gt;ip_addr&lt;/code&gt; field to the &lt;code&gt;Response&lt;/code&gt; struct and followed the breadcrumb of the Rust compiler. Quickly, I was able to figure out where the code should go.&lt;/p&gt;

&lt;p&gt;One issue with it was that &lt;a href="https://docs.rs/curl/latest/curl/easy/struct.Easy2.html#method.primary_ip" rel="noopener noreferrer"&gt;libcurl only gives you a string slice&lt;/a&gt; (&lt;code&gt;&amp;amp;str&lt;/code&gt;) of the IP address. So if I want to store it using the standard library enum &lt;code&gt;std::net::IpAddr&lt;/code&gt;, you have to convert it, and this conversion could fail. The maintainer suggested we create an intermediate struct for the response module, and only convert it if it's necessary. This way, if the user doesn't have any assert on IP address, there wouldn't be any run time error even if the address is invalid. &lt;/p&gt;

&lt;p&gt;We had &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3106#issuecomment-2635089587" rel="noopener noreferrer"&gt;some more discussion&lt;/a&gt; on the specifics, but nothing major happened afterwards.&lt;/p&gt;

&lt;h3&gt;
  
  
  📝 (Attempt to) Implement IP Address Asserts
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://hurl.dev/docs/asserting-response.html" rel="noopener noreferrer"&gt;The &lt;code&gt;Asserts&lt;/code&gt; field&lt;/a&gt; in Hurl allows you to specify conditions which the response has to meet. It's an extremely useful feature for testing.&lt;/p&gt;

&lt;p&gt;I used a similar strategy as a start - I found an enum called &lt;code&gt;QueryValue&lt;/code&gt; that seemed like it had to do with asserts, so I added another variant &lt;code&gt;QueryValue::Ip&lt;/code&gt;, and then I followed the compiler's messages. The problem this time was that, the messages took me all over the project and I was completely lost. It was so overwhelming that I had to pause.&lt;/p&gt;

&lt;p&gt;Feeling confused, I spent quite some time reading the code. Although I still can't say I fully understand it, I made a simple diagram to help me visualize it:&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%2Fvkxn945ezw5ipe55ih8z.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%2Fvkxn945ezw5ipe55ih8z.png" alt="Hurl assert feature diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obviously, this is overly-simplified and may not even be correct. But the idea is that some kind of information is taken from both the response and the Hurl file. Then they are processed into results and asserts are performed between these results.&lt;/p&gt;

&lt;p&gt;After some tinkering, I had the basic assert feature working:&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%2Fqk51xs6lcd4dbyeo661a.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%2Fqk51xs6lcd4dbyeo661a.png" alt="Assert working as intended"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's still problem: As a part of the feature request, the maintainer wants to also be able to assert the IP version , i.e. IPv4/IPv6. In this context, it makes more sense to model these queries into &lt;code&gt;std::net::IpAddr&lt;/code&gt;, since it's an enum with already built-in variants &lt;code&gt;IpAddr::V4&lt;/code&gt; and 'IpAddr::V6'. However, in order to support certain assert features like &lt;code&gt;contains&lt;/code&gt; or &lt;code&gt;matches&lt;/code&gt;, these queries have to be strings.&lt;/p&gt;

&lt;p&gt;Another issue was with &lt;a href="https://en.wikipedia.org/wiki/IPv6#Address_representation" rel="noopener noreferrer"&gt;IPv6 abbreviation&lt;/a&gt;. For example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;2001:0DB8:0032:0000:0000:0000:0000:FFFF&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2001:0DB8:0032:0:0:0:0:FFFF&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2001:0DB8:32:0:0:0:0:FFFF&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2001:DB8:32::FFFF&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of the above are the same IP address. If we want to implement it as a string, users might not know what type of abbreviation to expect&lt;/p&gt;

&lt;p&gt;I posted &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3106#issuecomment-2639835213" rel="noopener noreferrer"&gt;another comment&lt;/a&gt; about this situation and this is where I'm at right now. Let's see what the maintainer would say 😆&lt;/p&gt;
&lt;/div&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
      <category>rust</category>
    </item>
    <item>
      <title>Sprint 1 - Research Time!</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Sat, 01 Feb 2025 04:34:52 +0000</pubDate>
      <link>https://dev.to/theoforger/sprint-1-research-time-1cp1</link>
      <guid>https://dev.to/theoforger/sprint-1-research-time-1cp1</guid>
      <description>&lt;p&gt;Our first 2-week sprint came to an end. During this week, not much happened code-wise. However, working on these projects had led me to some interesting findings. And I'll be sharing all that right here!&lt;/p&gt;

&lt;h2&gt;
  
  
  🌐 Hurl
&lt;/h2&gt;

&lt;p&gt;(&lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3672" rel="noopener noreferrer"&gt;Link to PR&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This would be my last PR regarding the &lt;code&gt;header&lt;/code&gt; option feature. And I'm happy to report that I'm officially responsible for and in charge of this feature 🤪!&lt;/p&gt;

&lt;p&gt;This PR was essentially the reverse of &lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3617" rel="noopener noreferrer"&gt;the previous one&lt;/a&gt;. This time, my contribution was to &lt;code&gt;hurlfmt&lt;/code&gt;. This tool, among other features, allows you to convert curl commands to hurl files. I enabled it to handle empty headers in this process. For example, if you prepare a file named &lt;code&gt;example&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# file: example&lt;/span&gt;
curl &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Empty-Header;'&lt;/span&gt; https://httpbin.org/status/200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;hurlfmt &lt;span class="nt"&gt;--in&lt;/span&gt; curl example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll get the same request in hurl file format (Notice that &lt;code&gt;;&lt;/code&gt; is replaced with &lt;code&gt;:&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET https://httpbin.org/status/200
Empty-Header:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rust Stuff
&lt;/h3&gt;

&lt;p&gt;Something interesting I encountered with &lt;code&gt;clippy&lt;/code&gt;: In my initial implementation, I used a combination of &lt;code&gt;ends_with()&lt;/code&gt; and slicing, like so:&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;trimmed_header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="nf"&gt;.trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;trimmed_header&lt;/span&gt;&lt;span class="nf"&gt;.ends_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.push_str&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;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;{}:"&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;trimmed_header&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;trimmed_header&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="o"&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;And once again, the Rust toolchain took babysitting to another level:&lt;br&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%2Fmq86ty2nfj8jqbsl4a78.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%2Fmq86ty2nfj8jqbsl4a78.png" alt="Clippy suggesting .strip_suffix()" width="800" height="398"&gt;&lt;/a&gt;&lt;br&gt;
The suggested fix used the &lt;code&gt;if let&lt;/code&gt; pattern matching syntax and the &lt;code&gt;strip_suffix&lt;/code&gt; method. If the header ends with an &lt;code&gt;;&lt;/code&gt;, it will match &lt;code&gt;Option::Some&lt;/code&gt;, and then I can use the stripped string for the new format. Perfect! I appreciate how the linter always encourages you to do things "the Rust way".&lt;/p&gt;
&lt;h3&gt;
  
  
  Time to Investigate!
&lt;/h3&gt;

&lt;p&gt;During my development, I discovered a bug where if I use a file like the &lt;code&gt;example&lt;/code&gt; above, &lt;code&gt;hurlfmt&lt;/code&gt; would simple panic. Later, I realized that it happens to any invalid headers. I decided to look into this.&lt;/p&gt;

&lt;p&gt;Time to use the good old debugger! After many breakpoints and step-overs, I narrowed down the cause to &lt;a href="https://github.com/Orange-OpenSource/hurl/blob/04c9ccb5cd5070db41e1fdc04baab4105e950b03/packages/hurl_core/src/parser/parsers.rs#L53" rel="noopener noreferrer"&gt;the request parser&lt;/a&gt;. Seems like if a header is not parsed properly, the parser would terminate early and assume the rest belongs to a different request. And of course, the text that follows does not actually define a new request - This causes the program to panic.&lt;/p&gt;

&lt;p&gt;To better explain this, I ran &lt;code&gt;hurlfmt&lt;/code&gt; twice and recorded the cursor positions after parsing the requests. Here are the results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;With a valid header&lt;/th&gt;
&lt;th&gt;With an invalid header&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2F1ahbqh9e46tpafhc773t.png" alt="The parser terminated at the end of the text" width="488" height="129"&gt;&lt;/td&gt;
&lt;td&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%2Fx5cz7tnq1gz34yw03e6s.png" alt="The parser terminated early" width="488" height="129"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The parser terminated at the end of the text&lt;/td&gt;
&lt;td&gt;The parser terminated early&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And if we look closer, we can find that the parser stopped right before the invalid header. Here's index 55 in the buffer:&lt;br&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%2Fn7psch7ajsmqmijwwuvg.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%2Fn7psch7ajsmqmijwwuvg.png" alt="parser stopped right before the invalid header" width="488" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since this part of the code was complete new territory to me, I filed &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3668" rel="noopener noreferrer"&gt;an issue&lt;/a&gt; and hoped the maintainers would have more ideas about this. So far there haven't been any updates. But we'll see how this goes.&lt;/p&gt;
&lt;h2&gt;
  
  
  🌠 Starchart
&lt;/h2&gt;

&lt;p&gt;(&lt;a href="https://github.com/DevelopingSpace/starchart/pull/788" rel="noopener noreferrer"&gt;Link to PR&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;After last week's decision to switch from ESLint to &lt;a href="https://oxc.rs/" rel="noopener noreferrer"&gt;Oxc&lt;/a&gt;, I've been doing research. For the most part, this is a very straightforward project. I simply removed all the ESLint dependencies and added &lt;code&gt;oxlint&lt;/code&gt; to the list. Everything seemed to work, mostly.&lt;/p&gt;

&lt;p&gt;To migrate the configurations, I referred to their &lt;a href="https://oxc.rs/docs/guide/usage/linter/config.html" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;. The Ocx linter has a very similar configuration file to ESLint. For the most part, I just copied over the specs from &lt;a href="https://github.com/DevelopingSpace/starchart/blob/7638f3b014b7763853bf2b9b8be35f40d261b923/.eslintrc.js" rel="noopener noreferrer"&gt;the original file&lt;/a&gt;, except for this one section:&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="kd"&gt;extends&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;@remix-run/eslint-config&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;@remix-run/eslint-config/node&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;plugin:playwright/playwright-test&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;prettier&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;Apparently, Oxc still &lt;a href="https://github.com/oxc-project/oxc/issues/6552" rel="noopener noreferrer"&gt;doesn't support&lt;/a&gt; the &lt;code&gt;extend&lt;/code&gt; option. Although the linter runs just fine without it, I'm not sure if this will lead to any problems in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plans for Sprint 2
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hurl - Support ip query for getting resolved response IP
&lt;/h3&gt;

&lt;p&gt;(&lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3106" rel="noopener noreferrer"&gt;#3106&lt;/a&gt;)&lt;br&gt;
For this issue I'll implement a new feature to allow users to assert the IP address for each response. This is going to be a new chapter for me since I'll be working on a different part of the project. I spent the last few months with options and requests, but this will be all about responses. Can't wait to find out what I'll learn next!&lt;/p&gt;

&lt;h3&gt;
  
  
  Starchart - ???
&lt;/h3&gt;

&lt;p&gt;Since this is my 20% focus and I'm not super familiar with this project, I asked the class for recommendations during this week's sprint meeting. The professor mentioned there's a bug where certain CSS doesn't load. However, there's no recorded steps to reproduce. I'll work with the other folks on this project and see if we can figure out the cause.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>rust</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Sprint 1 - So Far so Good</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Fri, 24 Jan 2025 23:17:40 +0000</pubDate>
      <link>https://dev.to/theoforger/sprint-1-so-far-so-good-4k13</link>
      <guid>https://dev.to/theoforger/sprint-1-so-far-so-good-4k13</guid>
      <description>&lt;p&gt;It's the first week of our first sprint! I can feel the pace picking up. Love it! Here's the works I've done:&lt;/p&gt;

&lt;h2&gt;
  
  
  🦀 Hurl
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use variables in integration test (&lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3610" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;This was a follow-up &lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3576#pullrequestreview-2544609831" rel="noopener noreferrer"&gt;from my previous PR&lt;/a&gt;. Continuing on the topic of headers, the maintainer suggested me to add an integration test which uses variables to configure headers.&lt;/p&gt;

&lt;p&gt;I actually didn't know this feature until then. I am always amazed by the niche features that Hurl has to offer. I guess the surprises just kept on coming! Essentially, you can have a hurl file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET https://example.org/
[Options]
header: {{my_header}}

GET https://example.com/
[Options]
header: not-from-variable
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and execute &lt;code&gt;hurl&lt;/code&gt; with &lt;code&gt;--variable&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;hurl hurl_file.hurl &lt;span class="nt"&gt;--variable&lt;/span&gt; &lt;span class="nv"&gt;my_header&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;from_variable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, you can apply headers to certain requests without having to type it out under every one of them. Neat!&lt;/p&gt;

&lt;p&gt;In this PR, I simply created a new integration test with this syntax, which was merged without any problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Allow empty headers (&lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3617" rel="noopener noreferrer"&gt;Link&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;This was also a follow-up, but from way back. &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3536" rel="noopener noreferrer"&gt;The issue&lt;/a&gt; was created back when I was adding the &lt;code&gt;--header&lt;/code&gt; option. In &lt;a href="https://github.com/Orange-OpenSource/hurl/issues/3504#issuecomment-2551774611" rel="noopener noreferrer"&gt;a comment&lt;/a&gt;, I expressed my confusion about the behavior if the header is empty. Later it evolved into a conversation between the maintainers and then the said issue.&lt;/p&gt;

&lt;p&gt;In case you don't know, here's how &lt;code&gt;curl&lt;/code&gt;(as well as &lt;code&gt;libcurl&lt;/code&gt;) handles it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remove an internal header by giving a replacement without content on the right side of the colon, as in: -H "Host:". If you send the custom header  with  no-value then its header must be terminated with a semicolon, such as -H "X-Custom-Header;" to send "X-Custom-Header:"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, the maintainers of Hurl decided that they would not keep this consistent with &lt;code&gt;curl&lt;/code&gt;. Instead, they wanted to use &lt;code&gt;Header:&lt;/code&gt; to simply set an empty header. If the ability to remove headers is needed, they could implement it as a separate option in the future.&lt;/p&gt;

&lt;p&gt;Other than this feature tweak, there's also a &lt;code&gt;--curl&lt;/code&gt; option in Hurl to convert hurl file specs to &lt;code&gt;curl&lt;/code&gt; commands. Because of this change in behavior, I also added some code to make sure this feature work as expected.&lt;/p&gt;

&lt;p&gt;TLDR: Now you can use &lt;code&gt;--header 'Header:'&lt;/code&gt; to set an empty header!&lt;/p&gt;

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

&lt;p&gt;My initial plan with Starchart was to simply update the dependencies. There had been a lot of development in this project this week, but all work was not done by the time I tested it.&lt;/p&gt;

&lt;p&gt;First of all, I noticed that despite most vulnerabilities being fixed, most packages were still extremely out-of-date. I randomly decided to update &lt;code&gt;eslint&lt;/code&gt;, or at least try to. Turned out there was a series of issues waiting ahead:&lt;/p&gt;

&lt;p&gt;As soon as I bumped up the version number of &lt;code&gt;eslint&lt;/code&gt;, I was greeted with a message:&lt;br&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%2Fjv22grkexl3d23vf57hk.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%2Fjv22grkexl3d23vf57hk.png" alt="ESlint deprecation message" width="800" height="294"&gt;&lt;/a&gt;&lt;br&gt;
Apparently, in version 9, ESLint decided to deprecate the &lt;code&gt;eslintrc&lt;/code&gt; configuration method, which this project is using. Since version 8 had already reached its end of life, migration was necessary.&lt;/p&gt;

&lt;p&gt;Not a big deal, I thought. I just needed to look up the migration guide. Fortunately, their official documentation had a &lt;a href="https://eslint.org/docs/latest/use/configure/migration-guide" rel="noopener noreferrer"&gt;detailed page&lt;/a&gt; on this matter and they even provided &lt;a href="https://www.npmjs.com/package/@eslint/migrate-config" rel="noopener noreferrer"&gt;a tool&lt;/a&gt; to automate this process.&lt;/p&gt;

&lt;p&gt;The migration was smooth but I ran into another issue:&lt;br&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%2Fu0pomec0fjj50cdldrmf.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%2Fu0pomec0fjj50cdldrmf.png" alt="Remix deprecation message" width="800" height="52"&gt;&lt;/a&gt;&lt;br&gt;
So yeah... More deprecation: This time it was the &lt;code&gt;@remix-run/eslint-config&lt;/code&gt; package. Looking through their &lt;a href="https://www.npmjs.com/package/@remix-run/eslint-config" rel="noopener noreferrer"&gt;description&lt;/a&gt; I realized that this tool relies on the old configuration method, so if I don't deal with this first, I couldn't do anything with ESLint either.&lt;/p&gt;

&lt;p&gt;Feeling puzzled, I created &lt;a href="https://github.com/DevelopingSpace/starchart/issues/786" rel="noopener noreferrer"&gt;an issue&lt;/a&gt; asking for more opinions. My professor later chimed in and suggested that we switch to &lt;a href="https://oxc.rs/" rel="noopener noreferrer"&gt;Oxc&lt;/a&gt;. He commented that "A tool should work for me, not me for it", which I 100% agree.&lt;/p&gt;

&lt;p&gt;I've heard good things about this tool before, and hey, it's written in Rust. How could I say no to that! 😆&lt;/p&gt;

&lt;h2&gt;
  
  
  👥 Sprint Meeting
&lt;/h2&gt;

&lt;p&gt;During our Thursday meeting we each demoed the progress on our work. Not gonna lie, I was still pretty anxious. &lt;/p&gt;

&lt;p&gt;Before the meeting I prepared a sheet with bullet points of what I wanted to say, but during the meeting I found myself not able to read it at all.&lt;/p&gt;

&lt;p&gt;During the demo, I caught myself getting lost in my speech. And my only fallback strategy was to tell the story chronologically. This might work in a blog post like this, but not in a presentation - Despite me including a lot of unnecessary details, I still couldn't tell if I got my points across or not.&lt;/p&gt;

&lt;p&gt;I think there's still a long way to go before I can be comfortable in this type of meetings, but I'm willing to keep practicing.&lt;/p&gt;

&lt;p&gt;Some of the feedback and things I learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bring in more empathy. Think from the listener's perspective. What do they want to know? What do they need to know?&lt;/li&gt;
&lt;li&gt;Think about what details are necessary to the audience. Some details might be important to me, but not necessarily to the listeners. Remove those that are not needed. &lt;/li&gt;
&lt;li&gt;Try making some simple slides. It might be better than looking back and forth between my screen and paper.&lt;/li&gt;
&lt;li&gt;Pre-record or screenshot the work while working on it, and save it for the demo.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>rust</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Back For More!</title>
      <dc:creator>TheoForger</dc:creator>
      <pubDate>Thu, 16 Jan 2025 01:39:38 +0000</pubDate>
      <link>https://dev.to/theoforger/back-for-more-km4</link>
      <guid>https://dev.to/theoforger/back-for-more-km4</guid>
      <description>&lt;p&gt;It's been a month since my last update. If you're reading this, hope you had a wonderful holiday/new year! It's a new semester, and I'm once again taking a course on open source. Except that this time, instead of the "touch-and-go &lt;a href="https://dev.to/theoforger/hacktoberfest-racap-8cc"&gt;hacktoberfest-style&lt;/a&gt;" contributions, we will stick to a couple of projects and really get involved. Sounds fantastic!&lt;/p&gt;

&lt;h2&gt;
  
  
  🏃‍♂️ Warm-ups
&lt;/h2&gt;

&lt;p&gt;One of the tasks this week is to try and set up these projects:&lt;/p&gt;

&lt;h3&gt;
  
  
  💬 ChatCraft.org
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org" rel="noopener noreferrer"&gt;Chatcraft&lt;/a&gt; is a web application to chat with various LLMs. It's tailored for programmers and supports some coding-specific features which you cannot find from general-purpose LLM providers.&lt;/p&gt;

&lt;p&gt;This project is under active development and regularly maintained. It comes with &lt;a href="https://github.com/tarasglek/chatcraft.org/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;detailed documentation&lt;/a&gt; on how to set up the dev environment. For me, it was a very simple process.&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%2F2w1lp1rfcapjtlod50q3.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%2F2w1lp1rfcapjtlod50q3.png" alt="ChatCraft running in terminal" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It worked just like that! No errors, no endless research and troubleshooting. Not a surprise from a well-maintained project! The only extra work I did was installing the &lt;code&gt;pnpm&lt;/code&gt; package manager, which was also easy.&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%2Faqdfmm0i1xiakm6rjdzh.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%2Faqdfmm0i1xiakm6rjdzh.png" alt="ChatCraft in browser" width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;According to our professor, &lt;a href="https://github.com/DevelopingSpace/starchart" rel="noopener noreferrer"&gt;Starchart&lt;/a&gt; was an old project from our college. Students could use this service to get a free subdomain as well as an SSL certificate. Unfortunately, it was not funded anymore. If only I knew this before, I could've used it for my home server haha.&lt;/p&gt;

&lt;p&gt;I set up the docker containers following the &lt;a href="https://github.com/DevelopingSpace/starchart/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;contribution guide&lt;/a&gt;. And I gotta say, it's always satisfying to watch &lt;code&gt;docker compose&lt;/code&gt; do its own thing. Feels like magic!&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%2Fgkveaka5ov35mz37lggw.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%2Fgkveaka5ov35mz37lggw.png" alt="Docker compose pulling images" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because this is an unmaintained project (&lt;a href="https://github.com/DevelopingSpace/starchart/commits/main/" rel="noopener noreferrer"&gt;last commit&lt;/a&gt; was from 2 years ago), I almost expected trouble before I even started. To my surprise, I didn't run into much issues here either, other than some warnings of vulnerabilities and deprecation, which was totally expected. Just your typical npm things.&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%2F1ilazu96p36ptivi1wqa.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%2F1ilazu96p36ptivi1wqa.png" alt="npm vulnerability warnings" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Despite the warnings, the server ran just fine. However, I'd imagine it to be a different story if I were to try and upgrade these packages. There would probably be breaking changes all over.&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%2Fc3yejqvups8zaw0pr8ov.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%2Fc3yejqvups8zaw0pr8ov.png" alt="Starchart running" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  📃 Plans for The Semester
&lt;/h2&gt;

&lt;p&gt;Last semester, I left off with &lt;a href="https://dev.to/theoforger/december-surely-looks-busy-139f"&gt;some unfinished work&lt;/a&gt; in the &lt;a href="https://github.com/Orange-OpenSource/hurl" rel="noopener noreferrer"&gt;Hurl&lt;/a&gt; project. And last week, I finally picked up the last piece of work and submitted &lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3576" rel="noopener noreferrer"&gt;a PR for it&lt;/a&gt;. To my surprise, it was accepted without any request for change. I felt kinda proud haha 😆.&lt;/p&gt;

&lt;p&gt;Other than another &lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3576#pullrequestreview-2544609831" rel="noopener noreferrer"&gt;followup feature request&lt;/a&gt;, I also asked them about potentially continuing my work in the Hurl project for this course, to which they &lt;a href="https://github.com/Orange-OpenSource/hurl/pull/3576#issuecomment-2588036567" rel="noopener noreferrer"&gt;responded positively&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;There are lots of issues in this project I want to work on. I believe this is a great opportunity to further my knowledge in the HTTP protocol as well as Rust. It's like a dream come true!&lt;/p&gt;

&lt;p&gt;Naturally, this is where I envision myself to spend most of my efforts in. And for a second project, I think I'll go with Starchart - with Hurl, I'll be regularly working on new features, fixing bugs, and writing tests. With Starchart, I'll focus more on maintenance. This way I can have a more balanced experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Conclusion
&lt;/h2&gt;

&lt;p&gt;Not gonna lie, I've been excited about this course throughout the entire holiday. Can't wait to get back to it and have more open source in my life 😆&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
  </channel>
</rss>
