<?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: Alex Martinez</title>
    <description>The latest articles on DEV Community by Alex Martinez (@devalexmartinez).</description>
    <link>https://dev.to/devalexmartinez</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F855072%2F999f04c7-d723-4a4e-9468-d1abde663488.png</url>
      <title>DEV Community: Alex Martinez</title>
      <link>https://dev.to/devalexmartinez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devalexmartinez"/>
    <language>en</language>
    <item>
      <title>Migrating a Wix blog to Markdown: the server-HTML trap and the zero-width regex that pegged my CPU</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Thu, 09 Jul 2026 20:00:45 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/migrating-a-wix-blog-to-markdown-the-server-html-trap-and-the-zero-width-regex-that-pegged-my-cpu-1lhc</link>
      <guid>https://dev.to/devalexmartinez/migrating-a-wix-blog-to-markdown-the-server-html-trap-and-the-zero-width-regex-that-pegged-my-cpu-1lhc</guid>
      <description>&lt;p&gt;I moved a 138-post blog off Wix onto a static Astro site. The migration ran with zero errors and was still quietly missing half of every tutorial: code blocks, images, the embedded video. This post is the technical version of what I learned, aimed at people who want to see the actual code, not just the takeaways. If you want the higher-level "should I even do this" write-up, that's &lt;a href="https://prostdev.com/post/migrating-a-blog-from-wix-to-astro/" rel="noopener noreferrer"&gt;over on my blog&lt;/a&gt;. This one is the engineering.&lt;/p&gt;

&lt;p&gt;Everything here is in an open-source, dependency-free repo (Node stdlib only): &lt;strong&gt;&lt;a href="https://github.com/alexandramartinez/wix-to-astro" rel="noopener noreferrer"&gt;github.com/alexandramartinez/wix-to-astro&lt;/a&gt;&lt;/strong&gt;. I'll link the exact files as I go.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Wix post is &lt;strong&gt;two documents&lt;/strong&gt;: the server HTML, and a pile of stuff Wix hydrates &lt;strong&gt;client-side&lt;/strong&gt; (Gist code, the YouTube player, galleries, buttons, comments). Any migration script sees only the first. The second vanishes with no error.&lt;/li&gt;
&lt;li&gt;So don't summarize the page, and don't run it through an "AI to Markdown" tool. &lt;strong&gt;Read the raw server HTML and convert the real tags.&lt;/strong&gt; It's lossless.&lt;/li&gt;
&lt;li&gt;The extractor is a single-pass tokenizer over the isolated article HTML. The one bug worth your attention is a &lt;strong&gt;zero-width regex match&lt;/strong&gt; that pegs a CPU core forever. Details below, because it's a fun one.&lt;/li&gt;
&lt;li&gt;What's client-rendered, no script can recover. A small &lt;strong&gt;QA linter&lt;/strong&gt; greps the output for the tells so you know where the by-hand work is. Never fabricate the gaps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why the obvious approaches fail
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"Just pipe each page through an LLM and ask for Markdown."&lt;/strong&gt; This was my first attempt. An LLM paraphrases your prose (so your exact wording is gone) and, worse, &lt;strong&gt;silently drops every code block&lt;/strong&gt;. For a tutorial blog that's the entire point of the post. I ran the whole catalog through before I noticed, then had to redo it. Determinism beats cleverness here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Use the Wix export / a generic HTML-to-MD converter."&lt;/strong&gt; Closer, but it trips on Wix's specific DOM shapes (nested lists, split bold runs, image blocks) and, critically, it can't recover what isn't in the HTML at all. Which brings us to the actual insight.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core insight: server HTML vs. client hydration
&lt;/h2&gt;

&lt;p&gt;Fetch a Wix post with &lt;code&gt;curl&lt;/code&gt; and read the raw bytes. A large chunk of what a human sees in the browser &lt;strong&gt;isn't there&lt;/strong&gt;. Wix ships a shell and hydrates the rest with JavaScript after load. So:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lives in the server HTML (recoverable by a script)&lt;/th&gt;
&lt;th&gt;Hydrated client-side (invisible to any server-HTML reader)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prose, headings, links, bold/italic&lt;/td&gt;
&lt;td&gt;GitHub Gist &lt;strong&gt;code embeds&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nested lists, blockquotes&lt;/td&gt;
&lt;td&gt;The companion &lt;strong&gt;YouTube player&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; code that was authored inline&lt;/td&gt;
&lt;td&gt;Image &lt;strong&gt;galleries / carousels&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inline images (as a Wix image block)&lt;/td&gt;
&lt;td&gt;Styled &lt;strong&gt;CTA buttons&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON-LD metadata (title, author, dates)&lt;/td&gt;
&lt;td&gt;The &lt;strong&gt;reader comment&lt;/strong&gt; thread&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The left column is the lossless ~20% a script nails. The right column is the ~80% that has to be recovered by hand from a live browser render or your own source files. &lt;strong&gt;No tool that reads server HTML can recover the right column&lt;/strong&gt; — mine included. Pretending otherwise is how you ship plausible-but-wrong tutorials.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the server HTML
&lt;/h2&gt;

&lt;p&gt;No headless browser, no API key. Just &lt;code&gt;fetch&lt;/code&gt; with a UA string, then isolate the article body between two Wix markers:&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;const&lt;/span&gt; &lt;span class="nx"&gt;bs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-hook="rcv-block-first"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-hook="post-footer"&lt;/span&gt;&lt;span class="dl"&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;be&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;bodyHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lastIndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wix's post pages occasionally return a JS shell with the body markers absent, so the fetch retries a few times and only accepts a response once a marker is present. (Full source: &lt;a href="https://github.com/alexandramartinez/wix-to-astro/blob/main/src/wix-extract.mjs" rel="noopener noreferrer"&gt;&lt;code&gt;src/wix-extract.mjs&lt;/code&gt;&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Metadata comes from the page's JSON-LD, which &lt;em&gt;is&lt;/em&gt; server-rendered:&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;const&lt;/span&gt; &lt;span class="nx"&gt;ld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;script type="application&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;ld&lt;/span&gt;&lt;span class="se"&gt;\+&lt;/span&gt;&lt;span class="sr"&gt;json"&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;([\s\S]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;?)&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;script&amp;gt;/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ld&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="c1"&gt;// meta.headline, meta.description, meta.author, meta.datePublished, meta.dateModified&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The tokenizer: sentinels + one combined regex
&lt;/h2&gt;

&lt;p&gt;The naive approach — a chain of &lt;code&gt;.replace()&lt;/code&gt; calls converting each tag type independently — loses &lt;strong&gt;ordering&lt;/strong&gt;. You need images, code, and prose to come out in document order. So the extractor makes one ordered pass.&lt;/p&gt;

&lt;p&gt;Two block types can't be matched by a simple tag regex without eating their contents (code blocks contain arbitrary characters; list items nest). Those get pulled out first and replaced with &lt;strong&gt;sentinel placeholders&lt;/strong&gt; using a Unicode private-use-area character as a delimiter (so it can never collide with real content):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// code blocks -&amp;gt; ⟦CODE0⟧, ⟦CODE1⟧, ... (private-use char shown as ⟦⟧ for readability)&lt;/span&gt;
&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;pre&lt;/span&gt;&lt;span class="se"&gt;\b[^&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;([\s\S]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;?)&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;pre&amp;gt;/gi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inner&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="nx"&gt;codes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;br&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\/?&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;/gi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&amp;gt;/g&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`⟦CODE&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;codes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="s2"&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;Then a single combined regex walks everything in order — real block tags, figures, and the placeholders — and emits a typed token stream:&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;const&lt;/span&gt; &lt;span class="nx"&gt;re&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;(h[1-6]|blockquote|p)&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;b[^&amp;gt;]*&amp;gt;([&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;s&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;S]*?)&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;1&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;   &lt;span class="c1"&gt;// 1,2: block + inner&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;|&amp;lt;figure&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;b[^&amp;gt;]*data-hook="figure-(IMAGE|VIDEO)"[&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;s&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;S]*?&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;/figure&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;|⟦LIST(&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;d+)⟧&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;   &lt;span class="c1"&gt;// 4&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;|⟦CODE(&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;d+)⟧&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 5&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for &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;m&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;re&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&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;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="c1"&gt;// ... figure IMAGE -&amp;gt; {img}, figure VIDEO -&amp;gt; {vid} (client-side, dropped)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A second pass renders each token to Markdown. Clean, ordered, lossless.&lt;/p&gt;

&lt;h2&gt;
  
  
  The war story: a zero-width match that never terminates
&lt;/h2&gt;

&lt;p&gt;Here's the one I want you to remember. An earlier version of that combined regex ended like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DON'T do this:&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;|⟦CODE(&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;d+)⟧&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;|&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;   &lt;span class="c1"&gt;// &amp;lt;- trailing empty alternative&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That trailing &lt;code&gt;|&lt;/code&gt; is an &lt;strong&gt;empty alternative&lt;/strong&gt;: it matches the empty string. A regex that can match zero-width will happily match at &lt;em&gt;every gap between characters&lt;/em&gt;. &lt;code&gt;matchAll&lt;/code&gt; handles that safely (it force-advances past a zero-width hit), but a hand-rolled loop that advances its own index based on the match — and treats a zero-width match as "nothing to skip" — never moves forward:&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;let&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... handle token ...&lt;/span&gt;
  &lt;span class="c1"&gt;// BUG: a zero-width match means m.index === re.lastIndex, so `pos` doesn't&lt;/span&gt;
  &lt;span class="c1"&gt;// advance and the next iteration matches the SAME empty string. Forever.&lt;/span&gt;
  &lt;span class="nx"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastIndex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// stays put on a zero-width hit&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a short post you might not notice. On an &lt;strong&gt;image-heavy&lt;/strong&gt; post (lots of gaps between &lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; blocks where the empty alternative can fire), it locks onto a zero-width match, the index stays put, and the loop spins on one position pegging a CPU core until you kill it. No error, no output, just a hot laptop.&lt;/p&gt;

&lt;p&gt;Two lessons, both cheap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Never leave an empty alternative in a combined regex.&lt;/strong&gt; Audit for a &lt;code&gt;|&lt;/code&gt; with nothing between it and a &lt;code&gt;)&lt;/code&gt; or the end of the pattern.&lt;/li&gt;
&lt;li&gt;If you must hand-roll an &lt;code&gt;exec&lt;/code&gt; loop over a global regex, &lt;strong&gt;guard zero-width matches&lt;/strong&gt; by bumping &lt;code&gt;lastIndex&lt;/code&gt; yourself: &lt;code&gt;if (m.index === re.lastIndex) re.lastIndex++;&lt;/code&gt;. Or just use &lt;code&gt;matchAll&lt;/code&gt;, which does it for you.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The fix in the repo was to drop the empty alternative entirely, and there's a comment in the source warning the next person (me, in six months) not to "simplify" it back in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Wix-specific paper cuts
&lt;/h2&gt;

&lt;p&gt;A generic converter gets these wrong. Each is a few lines once you know the shape.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nested lists.&lt;/strong&gt; Wix nests the child &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; &lt;em&gt;inside&lt;/em&gt; the parent &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;, before its &lt;code&gt;&amp;lt;/li&amp;gt;&lt;/code&gt;. A non-greedy &lt;code&gt;&amp;lt;li&amp;gt;...&amp;lt;/li&amp;gt;&lt;/code&gt; match stops at the child's &lt;code&gt;&amp;lt;/li&amp;gt;&lt;/code&gt;, merging parent and first child and destroying indentation. Fix: preprocess each &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; into a placeholder that carries its &lt;code&gt;aria-level&lt;/code&gt;, then reconstruct indentation from the level.&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="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;li&lt;/span&gt;&lt;span class="se"&gt;\b([^&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&amp;lt;p&lt;/span&gt;&lt;span class="se"&gt;\b[^&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;([\s\S]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;?)&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;p&amp;gt;/gi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/aria-level="&lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;"/&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="mi"&gt;1&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="nx"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inner&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`⟦LIST&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="s2"&gt;⟧`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// later: '  '.repeat(level - 1) + '- ' + inline(item.html)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bold with the space inside the marker.&lt;/strong&gt; Wix emits &lt;code&gt;&amp;lt;strong&amp;gt;Pick this &amp;lt;/strong&amp;gt;option&lt;/code&gt;. Trim the inner text and you get &lt;code&gt;**Pick this**option&lt;/code&gt;, gluing the bold to the next word. And a &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt; wrapping only whitespace becomes an empty &lt;code&gt;****&lt;/code&gt;. So emphasis conversion keeps leading/trailing spaces &lt;em&gt;outside&lt;/em&gt; the markers:&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;const&lt;/span&gt; &lt;span class="nx"&gt;lead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;trail&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Split bold runs.&lt;/strong&gt; Wix loves to split &lt;code&gt;**Remember:**&lt;/code&gt; into &lt;code&gt;&amp;lt;strong&amp;gt;Remember&amp;lt;/strong&amp;gt;&amp;lt;strong&amp;gt;:&amp;lt;/strong&amp;gt;&lt;/code&gt;, which converts to &lt;code&gt;**Remember****:**&lt;/code&gt;. The &lt;code&gt;****&lt;/code&gt; in the middle (a bold-close butting a bold-open) renders as a stray run. Collapsing every &lt;code&gt;****&lt;/code&gt; to nothing rejoins them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full-resolution images.&lt;/strong&gt; A Wix image URL in the page is a &lt;em&gt;resized transform&lt;/em&gt;: &lt;code&gt;static.wixstatic.com/media/&amp;lt;id&amp;gt;/v1/fill/w_740,h_...&lt;/code&gt; . Strip the &lt;code&gt;/v1/fill/...&lt;/code&gt; and request the bare &lt;code&gt;static.wixstatic.com/media/&amp;lt;id&amp;gt;&lt;/code&gt; to get the original upload, not a downscaled copy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The media prefix isn't hardcodable.&lt;/strong&gt; Every asset on a given Wix site shares one account prefix (&lt;code&gt;&amp;lt;prefix&amp;gt;_&amp;lt;hash&amp;gt;~mv2.&amp;lt;ext&amp;gt;&lt;/code&gt;), and it differs per account. Discover it from the hero (&lt;code&gt;og:image&lt;/code&gt;) so the tool works for anyone:&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;const&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/og:image&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*content="&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;"&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\/([&lt;/span&gt;&lt;span class="sr"&gt;a-z0-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;_&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-f0-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+~mv2&lt;/span&gt;&lt;span class="se"&gt;\.[&lt;/span&gt;&lt;span class="sr"&gt;a-z&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+/i&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[a-z0-9]+&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;&lt;strong&gt;Hero de-duplication.&lt;/strong&gt; The hero image also appears as the first in-body image. Track the &lt;code&gt;og:image&lt;/code&gt; id and skip the in-body copy so it isn't rendered twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Heading levels.&lt;/strong&gt; Your post title is the page's only &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, so body headings should start at &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;. The extractor finds the shallowest heading level in the body and shifts everything so the shallowest becomes &lt;code&gt;##&lt;/code&gt;, preserving the relative hierarchy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What migrates but comes out &lt;em&gt;wrong&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Beyond what's dropped, some things survive but mangled, because the HTML-to-MD step had no rule for the shape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tables&lt;/strong&gt; flatten into a stack of one-line paragraphs (no &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt;/list structure to key on). I deliberately &lt;strong&gt;don't&lt;/strong&gt; auto-rebuild these — inventing table structure risks fabricating a header row that wasn't there. Rebuild them by hand as GFM pipe tables, verbatim.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Doubled blockquote quotes:&lt;/strong&gt; many SSG typography themes add curly quotes via CSS &lt;code&gt;::before&lt;/code&gt;/&lt;code&gt;::after&lt;/code&gt;, and your migrated text already has the author's quotes, so they print twice. Fix in the theme CSS, not the Markdown.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The gaps don't announce themselves, so lint for them
&lt;/h2&gt;

&lt;p&gt;Because none of the dropped content throws an error, I wrote a QA linter (&lt;a href="https://github.com/alexandramartinez/wix-to-astro/blob/main/src/qa-check.mjs" rel="noopener noreferrer"&gt;&lt;code&gt;src/qa-check.mjs&lt;/code&gt;&lt;/a&gt;) that greps the &lt;em&gt;output&lt;/em&gt; &lt;code&gt;.md&lt;/code&gt; files for the known tells and prints where to look. It changes nothing and recovers nothing — it just points:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node src/qa-check.mjs ./out          &lt;span class="c"&gt;# add --mdx to also catch MDX build traps&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./out/array-string-key-dataweave.md
      9  leftover-toc?      hand-authored TOC that duplicates your SSG on-page nav
     20  mdx-raw-&amp;lt;          raw "&amp;lt;" in prose breaks an MDX build
     28  empty-alt          image has no alt text: images/array-string-key-dataweave-1.png
     ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It flags: empty image alt (&lt;code&gt;![](…)&lt;/code&gt;), a "paste this in:" code lead-in with no code after it (dropped Gist), an orphaned "prefer video" line (dropped embed), a gallery lead-in with no image, a leftover "In this post:" TOC, a run of short one-line paragraphs (a flattened table), and — with &lt;code&gt;--mdx&lt;/code&gt; — a raw &lt;code&gt;&amp;lt;&lt;/code&gt; in prose or &lt;code&gt;{&lt;/code&gt;/&lt;code&gt;}&lt;/code&gt; in alt text. It exits non-zero on any finding, so you can gate a build on it in CI.&lt;/p&gt;

&lt;p&gt;Every finding is a &lt;strong&gt;tell, not a certainty&lt;/strong&gt;. Confirm each against the live page, then recover it from a real source.&lt;/p&gt;

&lt;h2&gt;
  
  
  If your target is Astro/MDX specifically
&lt;/h2&gt;

&lt;p&gt;Two build traps bit me repeatedly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A raw &lt;code&gt;&amp;lt;&lt;/code&gt; in prose&lt;/strong&gt; is read as a JSX tag and fails the build. Extremely common in technical writing: &lt;code&gt;Array&amp;lt;String&amp;gt;&lt;/code&gt;, &lt;code&gt;n &amp;lt;= 1&lt;/code&gt;, &lt;code&gt;&amp;lt;/Component&amp;gt;&lt;/code&gt;. Wrap in a code span or write &lt;code&gt;&amp;amp;lt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;{&lt;/code&gt; or &lt;code&gt;}&lt;/code&gt; in image alt text&lt;/strong&gt; starts a JSX expression and fails the build. Paraphrase code-ish alt text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;--mdx&lt;/code&gt; flag on the linter catches both before you hit a build error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating with an AI pair
&lt;/h2&gt;

&lt;p&gt;I did this migration with an AI assistant, and the failure mode there is obvious: an AI is &lt;em&gt;very&lt;/em&gt; willing to "recover" a dropped code block by writing one that looks right. That's the worst possible outcome for a tutorial. So the repo ships an &lt;a href="https://github.com/alexandramartinez/wix-to-astro/blob/main/AGENTS.md" rel="noopener noreferrer"&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;&lt;/a&gt; (works as &lt;code&gt;CLAUDE.md&lt;/code&gt; or a Cursor rules file) that encodes the discipline: run the scripts, run the linter, recover only from live sources or the author's files, and when you can't, &lt;strong&gt;leave a visible &lt;code&gt;TODO&lt;/code&gt; and ask — never a plausible guess.&lt;/strong&gt; The scripts do the lossless part; the guide keeps the human-in-the-loop part honest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/alexandramartinez/wix-to-astro
&lt;span class="nb"&gt;cd &lt;/span&gt;wix-to-astro

&lt;span class="c"&gt;# one post -&amp;gt; ./out/&amp;lt;slug&amp;gt;.md + ./out/images/&amp;lt;slug&amp;gt;-N.&amp;lt;ext&amp;gt;&lt;/span&gt;
node src/migrate-post.mjs &lt;span class="nt"&gt;--url&lt;/span&gt; https://YOURNAME.wixsite.com/website/post/my-post

&lt;span class="c"&gt;# a whole blog: set WIX_SITE in .env (it auto-discovers posts from the sitemap)&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
node &lt;span class="nt"&gt;--env-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.env examples/migrate-all.mjs

&lt;span class="c"&gt;# then audit what came across&lt;/span&gt;
node src/qa-check.mjs ./out &lt;span class="nt"&gt;--mdx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No dependencies, Node 18+ (the batch &lt;code&gt;--env-file&lt;/code&gt; path wants 20.6+).&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule
&lt;/h2&gt;

&lt;p&gt;Whatever tooling you use, mine included: &lt;strong&gt;never invent the missing content.&lt;/strong&gt; Every recovered snippet, caption, table row, or comment comes verbatim from a real source, or it stays an honest gap. A tutorial with a plausible-but-wrong code block is worse than one with a visible hole, because the reader can't tell it's wrong.&lt;/p&gt;

&lt;p&gt;Repo: &lt;strong&gt;&lt;a href="https://github.com/alexandramartinez/wix-to-astro" rel="noopener noreferrer"&gt;github.com/alexandramartinez/wix-to-astro&lt;/a&gt;&lt;/strong&gt;. If you hit a Wix shape I didn't cover, open an issue — I'd like to know about it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>astro</category>
      <category>node</category>
    </item>
    <item>
      <title>Install ACB on Cursor</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Wed, 30 Jul 2025 15:48:12 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/install-acb-on-cursor-2h9f</link>
      <guid>https://dev.to/devalexmartinez/install-acb-on-cursor-2h9f</guid>
      <description>&lt;p&gt;You might be having issues to install the Anypoint Extension Pack on Cursor because it might not be showing up in the Extensions tab. Here's how to fix that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you have Git installed&lt;/li&gt;
&lt;li&gt;Open Cursor&lt;/li&gt;
&lt;li&gt;Open the VS Code settings (not Cursor settings)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj17q5ln1s2ru8fq61yna.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%2Fj17q5ln1s2ru8fq61yna.png" alt=" " width="524" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search for &lt;code&gt;marketplace&lt;/code&gt; and paste the following Service URL:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://marketplace.visualstudio.com/_apis/public/gallery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F771wzvblxxs3z1botf7b.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%2F771wzvblxxs3z1botf7b.png" alt=" " width="800" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Restart Cursor&lt;/li&gt;
&lt;li&gt;Go to Extensions and look for the &lt;code&gt;Anypoint Extension Pack&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp314v6zybpvwh8byhzs9.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%2Fp314v6zybpvwh8byhzs9.png" alt=" " width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Troubleshooting ACB Installation Issues</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Wed, 02 Jul 2025 22:00:56 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/troubleshooting-acb-installation-issues-463m</link>
      <guid>https://dev.to/devalexmartinez/troubleshooting-acb-installation-issues-463m</guid>
      <description>&lt;p&gt;If you’re running into strange errors when installing &lt;strong&gt;Anypoint Code Builder (ACB)&lt;/strong&gt;—like the dreaded &lt;code&gt;Mule Platform process finished. Please, restart.&lt;/code&gt;—follow the steps below to start fresh and resolve common problems.&lt;/p&gt;

&lt;p&gt;In this post, you'll find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to start from scratch (remove the extension and any cache for a fresh install)&lt;/li&gt;
&lt;li&gt;Some best practices when opening an existing project&lt;/li&gt;
&lt;li&gt;How to download and/or set up a new Mule Runtime and Java versions&lt;/li&gt;
&lt;li&gt;How to fix the &lt;code&gt;503&lt;/code&gt; error when using Autodiscovery&lt;/li&gt;
&lt;li&gt;How to fix the &lt;code&gt;400 INVALID_ASSET_METADATA&lt;/code&gt; error when deploying your scaffolded Mule app to CloudHub 2.0&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧹 Start from Scratch
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;These steps can clear out random issues and give you a clean slate to work from.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Uninstall the &lt;strong&gt;Anypoint Extension Pack&lt;/strong&gt; from VS Code:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flr3u3mwyy6mx6rul0fk6.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%2Flr3u3mwyy6mx6rul0fk6.png" alt="Uninstalling the Anypoint Extension Pack in VS Code" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confirm you have Git installed. If not, &lt;a href="https://git-scm.com/downloads" rel="noopener noreferrer"&gt;download it here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure your VS Code is up to date:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Help&lt;/strong&gt; &amp;gt; &lt;strong&gt;Check for Updates&lt;/strong&gt; (Windows/Linux)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code&lt;/strong&gt; &amp;gt; &lt;strong&gt;Check for Updates&lt;/strong&gt; (Mac)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzpaw27ibzi6ab237bu0f.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%2Fzpaw27ibzi6ab237bu0f.png" alt="Checking for updates in VS Code" width="562" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Completely close VS Code (e.g. &lt;code&gt;Cmd + Q&lt;/code&gt; on Mac).&lt;/li&gt;
&lt;li&gt;In your &lt;strong&gt;user folder&lt;/strong&gt;, search for the &lt;code&gt;AnypointCodeBuilder&lt;/code&gt; directory and delete it:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnogsa86u9sglipypd98.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%2Ftnogsa86u9sglipypd98.png" alt="AnypointCodeBuilder folder in the user directory" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Still in your user folder, open the &lt;code&gt;.vscode&lt;/code&gt; folder. You have two cleanup options:

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clean slate&lt;/strong&gt;: Delete the entire &lt;code&gt;extensions&lt;/code&gt; folder to reset all extensions (note: this removes all VS Code extensions).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selective cleanup&lt;/strong&gt;: Inside &lt;code&gt;.vscode/extensions&lt;/code&gt;, remove only the folders starting with &lt;code&gt;salesforce.mule&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnzmop513hgft3fx4bga.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%2Fpnzmop513hgft3fx4bga.png" alt=".vscode/extensions folder showing salesforce.mule folders" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reopen VS Code and reinstall the &lt;strong&gt;Anypoint Extension Pack&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8eu6vat8vd41ohf2o57.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%2Fd8eu6vat8vd41ohf2o57.png" alt="Installing the Anypoint Extension Pack" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ Once installed, wait for the extensions to finish loading completely. Most issues should now be resolved!&lt;/p&gt;




&lt;h2&gt;
  
  
  📁 Opening an Existing Project?
&lt;/h2&gt;

&lt;p&gt;If you're working on an existing ACB project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Always open the project from its root folder&lt;/strong&gt;—not from a workspace or subfolder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&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%2Furi0ab7stdy4f4c5ejgj.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%2Furi0ab7stdy4f4c5ejgj.png" alt="VS Code opened at the root folder of the project" width="736" height="702"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To double-check that your setup is working:

&lt;ol&gt;
&lt;li&gt;Try designing a new API spec or&lt;/li&gt;
&lt;li&gt;Create a simple integration first.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once those basic operations run smoothly, you're ready to explore the rest of your project. 🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  👟 Runtime download / version
&lt;/h2&gt;

&lt;p&gt;Once you open the project, it might ask you to download a Mule Runtime. You can either click the 'Set Versions' button or right click on a Mule Configuration File (XML file) and select &lt;strong&gt;Open Mule Project Properties&lt;/strong&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%2Fe0rc3r64d4o2j6ncpmkq.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%2Fe0rc3r64d4o2j6ncpmkq.png" alt=" " width="491" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select your Mule Runtime and Java Version and click on &lt;strong&gt;Apply&lt;/strong&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%2Flpoarnsw3ua2w4xzw67o.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%2Flpoarnsw3ua2w4xzw67o.png" alt=" " width="800" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will then ask you to sign in to Anypoint Platform in order to download the Mule Runtime. Follow the prompts to sign in. Once you log in, you will see your username at the bottom-right.&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%2F6i8uj4coenmatmkzydfu.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%2F6i8uj4coenmatmkzydfu.png" alt=" " width="291" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After it finishes downloading both (Mule/Java), you will find the standalone folders in your &lt;code&gt;AnypointCodeBuilder&lt;/code&gt; folder.&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%2F21nzg3atlnygqahc1qo4.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%2F21nzg3atlnygqahc1qo4.png" alt=" " width="767" height="341"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Fixing the &lt;code&gt;503&lt;/code&gt; Error
&lt;/h2&gt;

&lt;p&gt;If you're getting a &lt;strong&gt;503 error&lt;/strong&gt; when calling your running app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the ACB &lt;strong&gt;Settings&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77njywqbwvn8r9m9zq2k.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%2F77njywqbwvn8r9m9zq2k.png" alt="ACB settings interface in VS Code" width="768" height="684"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search for &lt;code&gt;Mule &amp;gt; Runtime: Default Arguments&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;At the &lt;strong&gt;end of the existing text&lt;/strong&gt;, append this flag:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-M-Danypoint.platform.gatekeeper=disabled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F1et4e26t04nk7i0jtzfc.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%2F1et4e26t04nk7i0jtzfc.png" alt="Setting the gatekeeper argument in ACB settings" width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Restart your app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will disable the connection to Anypoint Platform when using Autodiscovery in your Mule app to be able to test locally. If you want to be able to connecto to Anypoint Platform to apply security policies or other settings, follow the same steps but add your Anypoint Platform credentials instead, 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;-M-Danypoint.platform.client_id=your_client_id -M-Danypoint.platform.client_secret=your_client_secret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For detailed information in both Studio and ACB, see &lt;a href="https://dev.to/devalexmartinez/quick-guide-to-applying-mulesofts-api-autodiscovery-4402"&gt;Quick guide to applying MuleSoft's API Autodiscovery&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Fixing the &lt;code&gt;400 INVALID_ASSET_METADATA&lt;/code&gt; Error
&lt;/h2&gt;

&lt;p&gt;When trying to deploy your Mule app to CloudHub 2.0 from ACB, you might get an error saying&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed to deploy to CloudHub 2.0: 
PUBLISH 400: INVALID_ASSET_METADATA. 
The asset is invalid. 
Error while trying to set type: app. 
Expected type is: rest-api.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fipcf3r4a6v8wsfy4d8e6.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%2Fipcf3r4a6v8wsfy4d8e6.png" alt=" " width="800" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason is that the &lt;code&gt;artifactId&lt;/code&gt; is the same in both:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;API Spec published in Exchange&lt;/li&gt;
&lt;li&gt;Mule project implementation in ACB&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, it's expecting you to publish a &lt;code&gt;rest-api&lt;/code&gt; (the api spec that is already in Exchange) but you're trying to publish an &lt;code&gt;app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To fix it, change the &lt;code&gt;artifactId&lt;/code&gt; you have on the Mule project in the &lt;code&gt;pom.xml&lt;/code&gt; file and retry deploying to CH2.&lt;/p&gt;

</description>
      <category>anypointcodebuilder</category>
      <category>acb</category>
      <category>mulesoft</category>
      <category>vscode</category>
    </item>
    <item>
      <title>List of AsyncAPI servers in MuleSoft</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Tue, 22 Oct 2024 15:54:17 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/list-of-asyncapi-servers-in-mulesoft-5a4h</link>
      <guid>https://dev.to/devalexmartinez/list-of-asyncapi-servers-in-mulesoft-5a4h</guid>
      <description>&lt;p&gt;After the October '24 release of Anypoint Code Builder, the AsyncAPI specification/implementation process in MuleSoft now supports the following message brokers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AnypointMQ&lt;/li&gt;
&lt;li&gt;Kafka&lt;/li&gt;
&lt;li&gt;Solace&lt;/li&gt;
&lt;li&gt;Salesforce Platform Events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I was reading through the documentation, I wasn't able to find a list of the servers that you need to set up in your AsyncAPI specification in order for the APIKit to pick up the correct configuration.&lt;/p&gt;

&lt;p&gt;I did find, however, an &lt;a href="https://docs.mulesoft.com/anypoint-code-builder/des-create-asyncapi-api-specs" rel="noopener noreferrer"&gt;example specification&lt;/a&gt; with the four available brokers. Thanks to this, I was able to get the list of protocols you need to use in your specifications.&lt;/p&gt;

&lt;p&gt;Here's the example from the docs (note that this applies to version 2.6 of AsyncAPI):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;AMQ-prod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https:://your_MQ_server_URL_here&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anypointmq&lt;/span&gt;
    &lt;span class="na"&gt;protocolVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Anypoint MQ broker&lt;/span&gt;
  &lt;span class="na"&gt;kafka-prod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_kafka_URL_here&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka broker&lt;/span&gt;
  &lt;span class="na"&gt;sfpubsub-prod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;salesforcepubsub&lt;/span&gt;
      &lt;span class="na"&gt;protocolVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api.pubsub.salesforce.com&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Salesforce pub sub for Platform events production&lt;/span&gt;
  &lt;span class="na"&gt;solace-server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;solace&lt;/span&gt;
    &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1000'&lt;/span&gt;
    &lt;span class="na"&gt;bindings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;solace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;msgVpn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_solace_vpn_here&lt;/span&gt;
        &lt;span class="na"&gt;bindingVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.4.0&lt;/span&gt;
    &lt;span class="na"&gt;protocolVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.0&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mySolaceURL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see from the previous code, not all of them are set up the same way. For example, Solace needs way more configurations than Kafka or AnypointMQ. It also looks like the Salesforce configuration is static since it's using a specific URL.&lt;/p&gt;

&lt;p&gt;Anyway, hope this list helps someone else out there who is not sure how to set up a specific server for your AsyncAPI specification in MuleSoft.&lt;/p&gt;

</description>
      <category>mulesoft</category>
      <category>asyncapi</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>Quick fix: 'Error: Process completed with exit code 1' in GitHub Actions with regex</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Thu, 19 Sep 2024 21:11:13 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/quick-fix-error-process-completed-with-exit-code-1-in-github-actions-with-regex-2892</link>
      <guid>https://dev.to/devalexmartinez/quick-fix-error-process-completed-with-exit-code-1-in-github-actions-with-regex-2892</guid>
      <description>&lt;p&gt;In summary, I was running GitHub Actions and I had a regex expression using &lt;code&gt;grep&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="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-Eo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="s2"&gt;+[.]&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="s2"&gt;+[.]&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="s2"&gt;+"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was to retrieve a version number from a line. For example, &lt;strong&gt;1.1.0&lt;/strong&gt;. The solution worked locally, but it failed in my CI/CD.&lt;/p&gt;

&lt;p&gt;Then, I found out this issue: &lt;a href="https://stackoverflow.com/questions/72087092/grep-failing-in-github-action-working-locally" rel="noopener noreferrer"&gt;Grep failing in GitHub Action, working locally&lt;/a&gt; and you can see from there the fix:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgiwkzlf4mi5pzg4353v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgiwkzlf4mi5pzg4353v.png" alt="StackOverflow response" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So that's what I did, and BOOM it worked!&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="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-Eo&lt;/span&gt; &lt;span class="s2"&gt;"[0-9]+[.][0-9]+[.][0-9]+"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just writing it out here so I remember how I fixed it in case I see the error again :D&lt;/p&gt;

&lt;p&gt;Also here are some screenshots from my actual pipeline:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cafbzew64jk3lirimt4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cafbzew64jk3lirimt4.png" alt="github action showing the error" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Success&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F908cinm41h4bvpznmzub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F908cinm41h4bvpznmzub.png" alt="github action showing the solution" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Quick fix: com.github.everit-org.json-schema:org.everit.json.schema:jar:1.12.2 was not found</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Tue, 17 Sep 2024 18:13:22 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/quick-fix-comgithubeverit-orgjson-schemaorgeveritjsonschemajar1122-was-not-found-1ej0</link>
      <guid>https://dev.to/devalexmartinez/quick-fix-comgithubeverit-orgjson-schemaorgeveritjsonschemajar1122-was-not-found-1ej0</guid>
      <description>&lt;p&gt;I've been having this issue in several Mule applications, but all of them happen while I'm trying to use CI/CD pipelines. &lt;/p&gt;

&lt;p&gt;The full thing I got was this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;org.mule.maven.client.api.exception.BundleDependencyNotFoundException: org.eclipse.aether.resolution.ArtifactResolutionException: com.github.everit-org.json-schema:org.everit.json.schema:jar:1.12.2 was not found in https://maven.anypoint.mulesoft.com/api/v3/maven during a previous attempt. This failure was cached in the local repository and resolution is not reattempted until the update interval of anypoint-exchange-v3 has elapsed or updates are forced

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

&lt;/div&gt;



&lt;p&gt;In summary, this happens because the &lt;code&gt;repositories&lt;/code&gt; you are using in your &lt;code&gt;pom.xml&lt;/code&gt; don't include this dependency that is needed from MuleSoft for something.&lt;/p&gt;

&lt;p&gt;This last time I encountered it, I fixed it using the Nexus public repo (because my specific use case doesn't use the Nexus credentials).&lt;/p&gt;

&lt;p&gt;Add this to your &lt;code&gt;pom.xml&lt;/code&gt; under the &lt;code&gt;&amp;lt;repositories&amp;gt;&lt;/code&gt; tag to fix it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;repository&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;Nexus&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Nexus Public Repository&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://repository-master.mulesoft.org/nexus/content/groups/public/&lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;layout&amp;gt;&lt;/span&gt;default&lt;span class="nt"&gt;&amp;lt;/layout&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/repository&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Here's the repo where I did this fix: &lt;a href="https://github.com/alexandramartinez/squirrel-app/" rel="noopener noreferrer"&gt;squirrel-app&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You don't need to set up Nexus credentials or anything on &lt;code&gt;settings.xml&lt;/code&gt;. This should be good enough.&lt;/p&gt;

&lt;p&gt;If this doesn't fix your issue, please get in touch cause I want to make sure I got this fix right.&lt;/p&gt;

</description>
      <category>mulesoft</category>
      <category>cicd</category>
      <category>maven</category>
    </item>
    <item>
      <title>4 ways to retrieve your OrgID/groupID from Anypoint Platform</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Wed, 01 May 2024 16:43:58 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/4-ways-to-retrieve-your-orgidgroupid-from-anypoint-platform-2e71</link>
      <guid>https://dev.to/devalexmartinez/4-ways-to-retrieve-your-orgidgroupid-from-anypoint-platform-2e71</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: the ids and credentials in this article are no longer available.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  From Access Management
&lt;/h2&gt;

&lt;p&gt;In Anypoint Platform, head to &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Business Groups&lt;/strong&gt; and select the Business Group you want to retrieve the ID from. You will see the &lt;strong&gt;Business Group ID&lt;/strong&gt; in the &lt;strong&gt;Settings&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F27nqdr9vc0lphp1wjn1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F27nqdr9vc0lphp1wjn1o.png" alt="Screenshot from Access Management"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this screen, you will also find more information like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;organization's client id/secret&lt;/strong&gt; - which are normally used from Anypoint Studio to test API Autodiscovery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;organization domain&lt;/strong&gt; - useful to access your Exchange public portal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus, if you go to the &lt;strong&gt;Environments&lt;/strong&gt; tab, you will be able to retrieve each &lt;strong&gt;environment's client id/secret&lt;/strong&gt;, which are useful for API Autodiscovery and other features.&lt;/p&gt;

&lt;h2&gt;
  
  
  From API Manager's URL
&lt;/h2&gt;

&lt;p&gt;In Anypoint Platform, head to &lt;strong&gt;API Manager&lt;/strong&gt;. Take a look at the URL in your browser. Your organization ID is the one after the &lt;code&gt;organizations/&lt;/code&gt; part.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fv9hc1rew5zylg0ol7c4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fv9hc1rew5zylg0ol7c4m.png" alt="Screenshot of the URL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's my URL as example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

https://anypoint.mulesoft.com/apimanager/sf-7743/#/organizations/4500658a-7637-4fcf-bc7d-51d1feb28edb/environments/f2346118-f56d-4a11-8009-491e6f9ed6d9/apis


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

&lt;/div&gt;

&lt;p&gt;In this URL, you will also find more information like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;organization domain&lt;/strong&gt; - in this example it would be &lt;code&gt;sf-7743&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;environment ID&lt;/strong&gt; - in this example it would be &lt;code&gt;f2346118-f56d-4a11-8009-491e6f9ed6d9&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  From API Manager's UI
&lt;/h2&gt;

&lt;p&gt;In Anypoint Platform, head to &lt;strong&gt;API Manager&lt;/strong&gt; and click on the &lt;strong&gt;Environment information&lt;/strong&gt; (ℹ️) button, next to the &lt;strong&gt;Add API&lt;/strong&gt; button. You will see the &lt;strong&gt;Business Group ID&lt;/strong&gt; in this prompt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fab7356uyxt6k51hw1ilx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fab7356uyxt6k51hw1ilx.png" alt="Environment information from API Manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this prompt, you will also find more information like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;environment id&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;environment's&lt;/strong&gt; client id/secret&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;organization's&lt;/strong&gt; client id/secret&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using the Anypoint Platform Chrome Extension
&lt;/h2&gt;

&lt;p&gt;You can download this chrome extension &lt;a href="https://chromewebstore.google.com/detail/gofndnflkobgljnjjalmehnlamoifmhc" rel="noopener noreferrer"&gt;here&lt;/a&gt;. It was created by &lt;a href="https://www.linkedin.com/in/yucemoran/" rel="noopener noreferrer"&gt;Edgar Moran&lt;/a&gt;, MuleSoft Ambassador. I cannot recommend this extension enough!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fnr6qsu2ppyffj16vzap4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fnr6qsu2ppyffj16vzap4.png" alt="Screenshot of the Anypoint Platform Chrome Extension to retrieve the organization id"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Besides helping you retrieve the organization id, you can also find the environment id and the token to connect Anypoint Platform :) ...and more!!&lt;/p&gt;

</description>
      <category>mulesoft</category>
      <category>tips</category>
    </item>
    <item>
      <title>An interesting Mule app to create complex MUnits</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Tue, 16 Apr 2024 17:03:54 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/an-interesting-mule-app-to-create-complex-munits-5od</link>
      <guid>https://dev.to/devalexmartinez/an-interesting-mule-app-to-create-complex-munits-5od</guid>
      <description>&lt;p&gt;This is a Mule application making use of Anypoint MQ and demonstrating how to use MUnit to create significant tests for different scenarios. Using spy, verify call, assertions, mock, and more.&lt;/p&gt;

&lt;p&gt;You can find the repo with the full code &lt;a href="https://github.com/alexandramartinez/my-process-api-munits" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.twitch.tv/?video=2121384816&amp;amp;parent=dev.to&amp;amp;autoplay=false" height="399" width="710"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The flows
&lt;/h2&gt;

&lt;p&gt;In summary, the main flow has a Subscriber to &lt;code&gt;queue1&lt;/code&gt;. Once the message is processed, it's attempted to be sent in an HTTP Request to an &lt;strong&gt;HR API&lt;/strong&gt;. The issue with this external API, is that it's not reliable and is often down. So, the code challenge was to be able to create a flow that could retry to send the RQ n amount of times before sending the message back to the queue. This was solved with an &lt;strong&gt;Until Successful&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2mvvd3y9ed6j65i9to6v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2mvvd3y9ed6j65i9to6v.png" alt="Image description" width="620" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second issue is that not all errors should be interpreted or processed the same way. If the API returned a Connectivity error, the flow is supposed to keep trying. But what if it's not a connectivity error and it's a bad request or an internal server error? Then we don't want to keep trying with the same request over and over again. We want to discard it and send an error to the &lt;code&gt;queue2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For this, an Error Continue needed to be put in place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sn1b9hbj3tt72cqotng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sn1b9hbj3tt72cqotng.png" alt="Image description" width="287" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now if the error is indeed a connectivity issue, then the error is returned with the &lt;strong&gt;On Error Propagate&lt;/strong&gt; to the Until Successful so it can be tried again. But if the error is anything else, like a bad request, then the message is processed as an Error Response and is sent to the &lt;code&gt;queue2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This way, the Until Successful won't be tried again because the message is interpreted as a successful response, but the payload contains the error message.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tests
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Happy Path
&lt;/h3&gt;

&lt;p&gt;The first test makes sure the happy path is working properly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wcasgbdntwyxum5o7j2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wcasgbdntwyxum5o7j2.png" alt="Image description" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a bunch of &lt;code&gt;Verify call&lt;/code&gt; components that help us make sure certain components are executed exactly the number of times they're supposed to be executed. We also have &lt;code&gt;Mock&lt;/code&gt;s for the calls to external systems, including Anypoint MQ.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frd5j3qdjuff7pkqxks39.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frd5j3qdjuff7pkqxks39.png" alt="Image description" width="625" height="868"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, none of the On Error Propagate/Continue were executed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bad Request
&lt;/h3&gt;

&lt;p&gt;As we learned from the description of the flows, we only want to keep trying to call the API if the error is a connectivity error. If not, we want to acknowledge the message from the queue and send the error response to the &lt;code&gt;queue2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp56ffzi39q74j6o3z1j5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp56ffzi39q74j6o3z1j5.png" alt="Image description" width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This test is a lot like the previous one. But take a look at the &lt;code&gt;Verify Call&lt;/code&gt;s. Their numbers change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4g1hmnnj6xshhlpvwl9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4g1hmnnj6xshhlpvwl9e.png" alt="Image description" width="625" height="868"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now instead of creating the successful response, the flow went to the On Error Continue to create the error response and send it to &lt;code&gt;queue2&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connectivity Issues 1
&lt;/h3&gt;

&lt;p&gt;In this test, we are mocking the connectivity error from the API call so we can make sure that the Until Successful is exhausted and the queue message is being put back into the queue with the NACK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6bf5vparwiwvnsz5qh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6bf5vparwiwvnsz5qh0.png" alt="Image description" width="448" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, there are no assertions in this test. That is because we are expecting an error back from the main flow. Once the error reaches the test, the assertions are not executed. So how do we know this is the expected error? By configuring the error as expected from the test's configuration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc48w53zk9oipcgylaobf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc48w53zk9oipcgylaobf.png" alt="Image description" width="491" height="706"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This way, we are expecting to receive the &lt;code&gt;RETRY_EXHAUSTED&lt;/code&gt; error from the Until Successful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzl7p19cg1bobokm1xb36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzl7p19cg1bobokm1xb36.png" alt="Image description" width="623" height="870"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Connectivity Issues 2
&lt;/h3&gt;

&lt;p&gt;Another way to test the same error scenario, but with actual assertions, is with the Try/Catch scope.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhu5gvybsj5bb23j7sh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhu5gvybsj5bb23j7sh0.png" alt="Image description" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This way, we are still making sure the &lt;code&gt;RETRY_EXHAUSTED&lt;/code&gt; error is correctly being returned (and nothing else), and we are able to actually run some validations. Like making sure the API request and the On Error Propagate are being executed exactly 3 times (because of the Until Successful settings).&lt;/p&gt;

</description>
      <category>mulesoft</category>
      <category>munit</category>
      <category>testing</category>
      <category>backend</category>
    </item>
    <item>
      <title>Quick guide to applying MuleSoft's API Autodiscovery</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Fri, 16 Feb 2024 18:32:03 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/quick-guide-to-applying-mulesofts-api-autodiscovery-4402</link>
      <guid>https://dev.to/devalexmartinez/quick-guide-to-applying-mulesofts-api-autodiscovery-4402</guid>
      <description>&lt;p&gt;Once you have created a Mule project and an API in API Manager, copy the &lt;strong&gt;API Instance ID&lt;/strong&gt; from API Manager (8-digit number).&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Add the API Autodiscovery Global Element
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: You can add the API ID directly in the Global Element or as a property&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Studio&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Studio, go to the &lt;strong&gt;Global Elements&lt;/strong&gt; tab and click on &lt;strong&gt;New&lt;/strong&gt;. Search for the Autodiscovery configuration. Add the &lt;strong&gt;API Instance ID&lt;/strong&gt; from API Manager to the API ID field. Select the main flow from the dropdown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ACB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In ACB, go to the XML view and start writing &lt;code&gt;autodiscovery&lt;/code&gt;. Select the &lt;code&gt;api-gateway:autodiscovery&lt;/code&gt; snippet. Add the &lt;strong&gt;API Instance ID&lt;/strong&gt; from API Manager to the &lt;code&gt;apiId&lt;/code&gt; field. Write the main flow on &lt;code&gt;flowRef&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Find your environment's client ID/Secret
&lt;/h2&gt;

&lt;p&gt;In Anypoint Platform, go to &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Business Groups&lt;/strong&gt; &amp;gt; select your business group &amp;gt; &lt;strong&gt;Environments&lt;/strong&gt; &amp;gt; &lt;strong&gt;Sandbox&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: See more ways to retrieve this info &lt;a href="https://dev.to/devalexmartinez/4-ways-to-retrieve-your-orgidgroupid-from-anypoint-platform-2e71"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Copy the Client ID and the Client Secret (click on &lt;strong&gt;Show&lt;/strong&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Add your Anypoint Platform credentials locally
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Studio&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Studio, open the &lt;strong&gt;Preferences&lt;/strong&gt; and navigate to &lt;strong&gt;Anypoint Studio&lt;/strong&gt; &amp;gt; &lt;strong&gt;API Manager&lt;/strong&gt;. Under Environment Credentials, add your Client ID and Client Secret. Click on &lt;strong&gt;Validate&lt;/strong&gt; &amp;gt; &lt;strong&gt;Apply and Close&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ACB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In VS Code, open the ACB tab and click the ⚙️ icon to open ACB's settings. Go to &lt;strong&gt;Mule &amp;gt; Runtime: Default Arguments&lt;/strong&gt; and append the following arguments at the end of the string.&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="nt"&gt;-M-Danypoint&lt;/span&gt;.platform.client_id&lt;span class="o"&gt;=&lt;/span&gt;your_client_id &lt;span class="nt"&gt;-M-Danypoint&lt;/span&gt;.platform.client_secret&lt;span class="o"&gt;=&lt;/span&gt;your_client_secret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Add your Anypoint Platform credentials in Runtime Manager
&lt;/h2&gt;

&lt;p&gt;Add your credentials to the properties tab in your Mule app deployed to Runtime Manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;anypoint.platform.client_id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_client_id&lt;/span&gt;
&lt;span class="py"&gt;anypoint.platform.client_secret&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_client_secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set up Gatekeeper as needed
&lt;/h2&gt;

&lt;p&gt;If you keep having a &lt;code&gt;503&lt;/code&gt; error code being returned, it may mean the API ID you provided is not connected to an API Manager instance. If you want to get rid of it, set up &lt;code&gt;anypoint.platform.gatekeeper=disabled&lt;/code&gt; in your runtime variables - &lt;strong&gt;this will disable the connection to API Manager&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;a) Studio: Set it up as an environment variable in your Run Configurations&lt;br&gt;
b) ACB: Set it up as an argument following the &lt;code&gt;-M-D...&lt;/code&gt; syntax from the previous point&lt;br&gt;
c) CloudHub: Set it up as a property&lt;br&gt;
d) Maven: Send it as a command argument&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This setting may be a security concern, make sure you discuss this with your team before setting it up or read more about it in the following resources&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Other resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.prostdev.com/post/how-to-add-jvm-command-line-arguments-to-the-mule-4-runtime-in-anypoint-code-builder-acb" rel="noopener noreferrer"&gt;How to add JVM/Command-line arguments to the Mule 4 Runtime in Anypoint Code Builder (ACB)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mulesoft.com/tutorials-and-howtos/getting-started/how-to-setup-api-autodiscovery-anypoint-studio/" rel="noopener noreferrer"&gt;How to set up API Autodiscovery in Anypoint Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.mulesoft.com/mule-gateway/mule-gateway-gatekeeper" rel="noopener noreferrer"&gt;Enhancing Security with Gatekeeper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mulesoft</category>
      <category>security</category>
      <category>api</category>
      <category>anypoint</category>
    </item>
    <item>
      <title>Quick guide to secure/encrypt your properties in MuleSoft</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Mon, 12 Feb 2024 17:34:48 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/quick-guide-to-secureencrypt-your-properties-in-mulesoft-n9k</link>
      <guid>https://dev.to/devalexmartinez/quick-guide-to-secureencrypt-your-properties-in-mulesoft-n9k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;This post is to generate your encrypted values by manually using the JAR file. You can also use the &lt;a href="https://secure-properties-api.us-e1.cloudhub.io/" rel="noopener noreferrer"&gt;(unofficial) UI&lt;/a&gt; or refer to &lt;a href="https://help.mulesoft.com/s/article/How-to-implement-the-secure-properties-tool-inside-an-API-to-encrypt-or-decrypt-with-plain-text-password" rel="noopener noreferrer"&gt;this article&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Download the Secure Properties Tool Jar file from the &lt;a href="https://docs.mulesoft.com/mule-runtime/latest/secure-configuration-properties#secure_props_tool" rel="noopener noreferrer"&gt;Mule docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see in the docs how to encrypt your properties with different scenarios, but the following scripts are the ones I use the most.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encrypt one value at a time
&lt;/h2&gt;

&lt;p&gt;I normally use the &lt;strong&gt;Blowfish&lt;/strong&gt; algorithm and the &lt;strong&gt;CBC&lt;/strong&gt; mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-cp&lt;/span&gt; secure-properties-tool.jar com.mulesoft.tools.SecurePropertiesTool &lt;span class="se"&gt;\&lt;/span&gt;
string &lt;span class="se"&gt;\&lt;/span&gt;
encrypt &lt;span class="se"&gt;\&lt;/span&gt;
Blowfish &lt;span class="se"&gt;\&lt;/span&gt;
CBC &lt;span class="se"&gt;\&lt;/span&gt;
your_secure_key &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"value_to_encrypt"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, just make sure to add &lt;code&gt;![]&lt;/code&gt; in your properties file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encrypt the whole file (per value)
&lt;/h2&gt;

&lt;p&gt;If you don't want to do the previous script for all of the values, you can also run this instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-cp&lt;/span&gt; secure-properties-tool.jar com.mulesoft.tools.SecurePropertiesTool &lt;span class="se"&gt;\&lt;/span&gt;
file &lt;span class="se"&gt;\&lt;/span&gt;
encrypt &lt;span class="se"&gt;\&lt;/span&gt;
Blowfish &lt;span class="se"&gt;\&lt;/span&gt;
CBC &lt;span class="se"&gt;\&lt;/span&gt;
your_secure_key &lt;span class="se"&gt;\&lt;/span&gt;
input_file.yaml &lt;span class="se"&gt;\&lt;/span&gt;
output_file.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will automatically add the &lt;code&gt;![]&lt;/code&gt; syntax to each value.&lt;/p&gt;

</description>
      <category>security</category>
      <category>encryption</category>
      <category>mulesoft</category>
      <category>mule4</category>
    </item>
    <item>
      <title>Quick reference: CI/CD for a Mule app using a Connected App</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Tue, 01 Aug 2023 16:07:24 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/quick-reference-cicd-for-a-mule-app-using-a-connected-app-jlj</link>
      <guid>https://dev.to/devalexmartinez/quick-reference-cicd-for-a-mule-app-using-a-connected-app-jlj</guid>
      <description>&lt;p&gt;This is intended as a short guide. For detailed instructions + video, please see &lt;a href="https://www.prostdev.com/post/how-to-set-up-a-ci-cd-pipeline-to-deploy-your-mulesoft-apps-to-cloudhub-using-github-actions" rel="noopener noreferrer"&gt;this series&lt;/a&gt;. You can also see &lt;a href="https://github.com/alexandramartinez/mulesoft-mfa-cicd" rel="noopener noreferrer"&gt;this repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connected App
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://anypoint.mulesoft.com/" rel="noopener noreferrer"&gt;Anypoint Platform&lt;/a&gt;, go to &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Connected Apps&lt;/strong&gt; &amp;gt; &lt;strong&gt;Create app&lt;/strong&gt;. Select &lt;code&gt;App acts on it's own behalf&lt;/code&gt;. Add the scopes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design Center Developer&lt;/li&gt;
&lt;li&gt;View Environment&lt;/li&gt;
&lt;li&gt;View Organization&lt;/li&gt;
&lt;li&gt;Profile&lt;/li&gt;
&lt;li&gt;Cloudhub Organization Admin&lt;/li&gt;
&lt;li&gt;Create Applications&lt;/li&gt;
&lt;li&gt;Delete Applications&lt;/li&gt;
&lt;li&gt;Download Applications&lt;/li&gt;
&lt;li&gt;Read Applications&lt;/li&gt;
&lt;li&gt;Read Servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copy &lt;code&gt;ID&lt;/code&gt; and &lt;code&gt;Secret&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions secrets
&lt;/h2&gt;

&lt;p&gt;In your GitHub repo, go to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Secrets and variables&lt;/strong&gt; &amp;gt; &lt;strong&gt;Actions&lt;/strong&gt; &amp;gt; &lt;strong&gt;New repository secret&lt;/strong&gt; and add the following secrets corresponding to your previous ID and Secret.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CONNECTED_APP_CLIENT_ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CONNECTED_APP_CLIENT_SECRET&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  build.yml
&lt;/h2&gt;

&lt;p&gt;In your Mule app's code or repo, create a &lt;code&gt;.github&lt;/code&gt; folder with a &lt;code&gt;workflows&lt;/code&gt; folder. Inside this, create a &lt;code&gt;build.yml&lt;/code&gt; and paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Deploy&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout this repo&lt;/span&gt;
          &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cache dependencies&lt;/span&gt;
          &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v3&lt;/span&gt;
          &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.m2/repository&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}&lt;/span&gt;
            &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;${{ runner.os }}-maven-&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up JDK &lt;/span&gt;&lt;span class="m"&gt;1.8&lt;/span&gt;
          &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v3&lt;/span&gt;
          &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;distribution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;zulu'&lt;/span&gt;
            &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build with Maven&lt;/span&gt;
          &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mvn -B package --file pom.xml -DskipMunitTests&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Stamp artifact file name with commit hash&lt;/span&gt;
          &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;artifactName1=$(ls target/*.jar | head -1)&lt;/span&gt;
            &lt;span class="s"&gt;commitHash=$(git rev-parse --short "$GITHUB_SHA")&lt;/span&gt;
            &lt;span class="s"&gt;artifactName2=$(ls target/*.jar | head -1 | sed "s/.jar/-$commitHash.jar/g")&lt;/span&gt;
            &lt;span class="s"&gt;mv $artifactName1 $artifactName2&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload artifact&lt;/span&gt; 
          &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v3&lt;/span&gt;
          &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;artifacts&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;target/*.jar&lt;/span&gt;

    &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
        &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout this repo&lt;/span&gt;
          &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cache dependencies&lt;/span&gt;
          &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v3&lt;/span&gt;
          &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.m2/repository&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}&lt;/span&gt;
            &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;${{ runner.os }}-maven-&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/download-artifact@v3&lt;/span&gt;
          &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;artifacts&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;
          &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;artifactName=$(ls *.jar | head -1)&lt;/span&gt;
            &lt;span class="s"&gt;mvn deploy -DskipMunitTests -DmuleDeploy \&lt;/span&gt;
             &lt;span class="s"&gt;-Dmule.artifact=$artifactName \&lt;/span&gt;
             &lt;span class="s"&gt;-Dclient.id="${{ secrets.CONNECTED_APP_CLIENT_ID }}" \&lt;/span&gt;
             &lt;span class="s"&gt;-Dclient.secret="${{ secrets.CONNECTED_APP_CLIENT_SECRET }}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  pom.xml
&lt;/h2&gt;

&lt;p&gt;Make sure the config matches your application. For example, &lt;code&gt;muleVersion&lt;/code&gt;, &lt;code&gt;applicationName&lt;/code&gt;, &lt;code&gt;environment&lt;/code&gt;, &lt;code&gt;region&lt;/code&gt;, and so on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mule.tools.maven&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mule-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${mule.maven.plugin.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;extensions&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/extensions&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Deployment config start --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;cloudHubDeployment&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;uri&amp;gt;&lt;/span&gt;https://anypoint.mulesoft.com&lt;span class="nt"&gt;&amp;lt;/uri&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;muleVersion&amp;gt;&lt;/span&gt;4.4.0&lt;span class="nt"&gt;&amp;lt;/muleVersion&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;applicationName&amp;gt;&lt;/span&gt;mulesoft-mfa-cicd&lt;span class="nt"&gt;&amp;lt;/applicationName&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;environment&amp;gt;&lt;/span&gt;Sandbox&lt;span class="nt"&gt;&amp;lt;/environment&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;workerType&amp;gt;&lt;/span&gt;MICRO&lt;span class="nt"&gt;&amp;lt;/workerType&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;region&amp;gt;&lt;/span&gt;us-east-2&lt;span class="nt"&gt;&amp;lt;/region&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;workers&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/workers&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;objectStoreV2&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/objectStoreV2&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;connectedAppClientId&amp;gt;&lt;/span&gt;${client.id}&lt;span class="nt"&gt;&amp;lt;/connectedAppClientId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;connectedAppClientSecret&amp;gt;&lt;/span&gt;${client.secret}&lt;span class="nt"&gt;&amp;lt;/connectedAppClientSecret&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;connectedAppGrantType&amp;gt;&lt;/span&gt;client_credentials&lt;span class="nt"&gt;&amp;lt;/connectedAppGrantType&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;env&amp;gt;&lt;/span&gt;${env}&lt;span class="nt"&gt;&amp;lt;/env&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/cloudHubDeployment&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Deployment config end --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Commit, push, and watch it run :)&lt;/p&gt;

</description>
      <category>mulesoft</category>
      <category>cicd</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Using time() and duration() in DataWeave for performance check</title>
      <dc:creator>Alex Martinez</dc:creator>
      <pubDate>Tue, 21 Mar 2023 16:02:44 +0000</pubDate>
      <link>https://dev.to/devalexmartinez/using-time-and-duration-in-dataweave-for-performance-check-1dkl</link>
      <guid>https://dev.to/devalexmartinez/using-time-and-duration-in-dataweave-for-performance-check-1dkl</guid>
      <description>&lt;p&gt;You can use &lt;a href="https://docs.mulesoft.com/dataweave/latest/dw-timer-functions-duration" rel="noopener noreferrer"&gt;&lt;code&gt;duration()&lt;/code&gt;&lt;/a&gt; to get the total number of milliseconds it took to execute a function.&lt;/p&gt;

&lt;p&gt;Script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%dw 2.0
output application/json
import duration from dw::util::Timer
fun myFunc() = [1, 2, 3] reduce $+$$
---
duration(() -&amp;gt; myFunc())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use &lt;a href="https://docs.mulesoft.com/dataweave/latest/dw-timer-functions-time" rel="noopener noreferrer"&gt;&lt;code&gt;time()&lt;/code&gt;&lt;/a&gt; to get an even more detailed result of when the function started and ended. This will give you more insight into the total time it took to execute.&lt;/p&gt;

&lt;p&gt;Script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%dw 2.0
output application/json
import time from dw::util::Timer
fun myFunc() = [1, 2, 3] reduce $+$$
---
time(() -&amp;gt; myFunc())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-03-21T16:00:21.487377Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-03-21T16:00:21.487408Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way you can use &lt;code&gt;-&lt;/code&gt; to get the total number of time.&lt;/p&gt;

&lt;p&gt;Script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%dw 2.0
output application/json
import time from dw::util::Timer
fun myFunc() = [1, 2, 3] reduce $+$$
var funcResult = time(() -&amp;gt; myFunc())
---
funcResult.end - funcResult.start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="s2"&gt;"PT0.000024S"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>mulesoft</category>
      <category>dataweave</category>
      <category>performance</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
