<?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: Aritra Karak</title>
    <description>The latest articles on DEV Community by Aritra Karak (@tr1ckydev).</description>
    <link>https://dev.to/tr1ckydev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1182667%2F21a57ab0-11c4-4976-9339-d696755051e1.jpg</url>
      <title>DEV Community: Aritra Karak</title>
      <link>https://dev.to/tr1ckydev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tr1ckydev"/>
    <language>en</language>
    <item>
      <title>tRPA - Remote Property Access</title>
      <dc:creator>Aritra Karak</dc:creator>
      <pubDate>Tue, 16 Apr 2024 09:34:28 +0000</pubDate>
      <link>https://dev.to/tr1ckydev/trpa-remote-property-access-817</link>
      <guid>https://dev.to/tr1ckydev/trpa-remote-property-access-817</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;How about a way to interconnect server-side and client-side javascript so that you can access server-side functions or properties from the client side just as you would on the server side? Sounds cool right? This project makes it happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Long back, NVIDIA had released their Chat with RTX application which allows you to upload your files and then query or chat with them using an LLM.&lt;br&gt;
I have been using Ollama for quite a while, which allows you to run LLMs locally on your device. It randomly struck my mind to create something similar but using Ollama APIs. So I started working on the project Chat with Ollama. It's still in its infancy but you can find the source &lt;a href="https://github.com/tr1ckydev/chat-with-ollama"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;While I was working on it, I wanted to use some server-side functions on the client side. To make it possible, I had to create API routes on my server that would invoke the server-side function, to which I had to make a fetch request from the client side to invoke it but I found it kind of tedious.&lt;/p&gt;

&lt;p&gt;So I started researching alternative ways for server-side invocation of functions from the client side. It didn't take me long to stumble upon the project called tRPC. I think most of you have already heard about it and for those who haven't, it lets you define procedures (i.e. functions) on the server side and allows you to call them from the client side without explicitly writing any API routes like before as it takes care of all that stuff internally. And not to mention the incredible TypeScript auto completions we get on the client side too. Pretty cool!&lt;/p&gt;

&lt;p&gt;But for some reason, I was too lazy to understand and write all that boilerplate code in my project just to access some functions. So an idea came to my mind, "Can I make something similar with almost no boilerplate code?". I came up with a rough plan for approaching this by having some fixed internal routes through which the functions needed to be invoked will be intercommunicated while providing a dead simple one-function API to the user on both sides.&lt;/p&gt;

&lt;p&gt;I dug deeper into how tRPC worked and I was right, it still uses normal HTTP requests under the hood to communicate with the server and execute procedures but hides this abstraction with a friendly API to define your procedures which can be accessed on the client side.&lt;/p&gt;

&lt;p&gt;At that point, I had gathered enough knowledge to bring my idea into reality. My initial prototype was accessing a server-side object property from the client side. It happened to be a success and the fun fact is that only two lines are needed to implement it in any existing project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// server.ts&lt;/span&gt;
&lt;span class="nf"&gt;exportToClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// client.ts&lt;/span&gt;
&lt;span class="nx"&gt;importFromServer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Exports&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can't get any simpler than this. Ain't it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Unveiling the insides
&lt;/h2&gt;

&lt;p&gt;Currently, there are 3 main underlying API routes: '/trpa/exports&lt;code&gt;,&lt;/code&gt;/trpa/access&lt;code&gt;, and&lt;/code&gt;/trpa/execute`. Let's dive into how they work.&lt;/p&gt;

&lt;p&gt;When the client first connects to the server, &lt;code&gt;importFromServer&lt;/code&gt; makes a call to &lt;code&gt;/trpa/exports&lt;/code&gt; and receives a JSON for the skeleton of the exported properties and functions. It then uses that to recursively create an Object with the same properties and functions and sets its getters to make an API call to either retrieve the property(&lt;code&gt;/trpa/access&lt;/code&gt;) or execute the function(&lt;code&gt;/trpa/execute&lt;/code&gt;) when accessed. In simple words, it clones the structure but sets the getters with API calls. You're essentially remotely accessing a property. So every access or execution has to be &lt;code&gt;await&lt;/code&gt;ed on the client side, a pretty unique concept I came up with, which is quite different to what tRPC does i.e. using a Proxy object. That's it! That's the entire concept of tRPA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus idea
&lt;/h2&gt;

&lt;p&gt;Till now all data are sent/received in the form of JSON, and function arguments are sent through URL parameters. However, the Request body supports more data types like ArrayBuffer, Blob, FormData, JSON, and text. We can take advantage of that to make more kinds of data possible to send/receive. So I came up with the function &lt;code&gt;asBody&lt;/code&gt; which can be imported both on the server and client side to tell tRPA to send that data through the Request/Response body. It returns an object with the value and the type of instance which I call decode strategy. This value is used by the receiving side to decode the body.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;Though it's a new concept inspired by tRPC, it does not try to be a competitor to it but rather an alternative allowing you to choose what fits best for your project. tRPA is far from being production-ready but stable enough to be used in your small web projects right now.&lt;/p&gt;

&lt;p&gt;Find this idea interesting? Want to contribute?&lt;br&gt;
Feel free to open PRs or issues or comment down your thoughts on this.&lt;/p&gt;

&lt;p&gt;Checkout the entire project here:&lt;br&gt;
&lt;a href="https://github.com/tr1ckydev/tRPA"&gt;https://github.com/tr1ckydev/tRPA&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>rpc</category>
      <category>typescript</category>
      <category>trpc</category>
    </item>
    <item>
      <title>Hyperimport - Import c, rust, zig etc. files in TypeScript</title>
      <dc:creator>Aritra Karak</dc:creator>
      <pubDate>Sat, 14 Oct 2023 19:05:16 +0000</pubDate>
      <link>https://dev.to/tr1ckydev/hyperimport-import-c-rust-zig-etc-files-in-typescript-1ia5</link>
      <guid>https://dev.to/tr1ckydev/hyperimport-import-c-rust-zig-etc-files-in-typescript-1ia5</guid>
      <description>&lt;p&gt;&lt;em&gt;"What? Did I read the title correct?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yes! Let's jump into an example right in the beginning, 'cause why not?&lt;/p&gt;

&lt;p&gt;You'll be able to do this,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;index.ts&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./add.rs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;add&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;add.rs&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;isize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;isize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;isize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and even more, like importing native C functions from libc in typescript. &lt;a href="https://github.com/tr1ckydev/hyperimport/wiki/Importing-libc-in-typescript"&gt;Check out the guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Wait! What?? How is that even possible!?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Long back, when I was working on the project &lt;a href="https://github.com/tr1ckydev/webview-bun"&gt;webview-bun&lt;/a&gt;, which essentially is an FFI wrapper of the webview library APIs for Bun. It randomly struck my mind, why can't I import the webview C source file directly into typescript, if through FFI API we can import functions from shared libraries which are essentially compiled from a source file like c, rust, zig, etc., how about I create a way to bridge importing functions in typescript with the source file and automate and the steps in between, in a way that it looks to the end user that they are directly importing from the source file while all the hard parts are managed automatically internally.&lt;/p&gt;

&lt;p&gt;I wrote a simple function called calc in zig to add two numbers. In typescript, I wrote an import function that would take the path to that zig file, spawn a child process to invoke the zig compiler to compile that file into a shared library file then open that shared library using FFI API and return the symbols which essentially contains the calc function. So when I used the function to import the zig file, those internal steps happened behind the scenes and the calc function worked. Then when I changed the operation inside the zig function from addition to subtraction and executed the typescript file, those steps happened again essentially recompiling the file and the new output reflected the changes. This is how the typescript file looked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;calc&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./calc.zig&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;calc&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://i.giphy.com/media/E3MQDZl9qsVwgnKA7b/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/E3MQDZl9qsVwgnKA7b/giphy.gif" alt="" width="600" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It appeared as if it was black magic in that function, importing the function directly from Zig but under the hood, the file is compiled into a shared library and it is importing from the library and not the source file itself. But, the syntax looked super clean and easy to comprehend. I recorded my screen showing this experimental prototype and posted it on &lt;a href=""&gt;Bun's discord&lt;/a&gt; server.&lt;/p&gt;

&lt;p&gt;Soon, Jarred came across the message and replied that I could make use of the buntime (we'll call runtime as buntime, 'cause why not) Plugin API and implement my logic as a plugin which would allow me to use ES6 imports instead of that weird looking import function.&lt;/p&gt;

&lt;p&gt;Honestly, before this, I never actually used the Plugin API, so I started diving into it. With some fair complications and a few rewrites, I was finally able to port that logic over to use the Plugin API. Now I could easily import the zig file using ES6 import syntax. Even though Typescript was still shouting at me because it doesn't know what calc.zig is or what the calc function is, it still blew my mind away because it looked terrifying.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;calc&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./calc.zig&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;calc&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, I decided to make it even more terrifying. I added types.&lt;/p&gt;

&lt;p&gt;Using typescript's &lt;a href="https://www.typescriptlang.org/docs/handbook/modules.html#wildcard-module-declarations"&gt;wildcard module declaration&lt;/a&gt; feature, I created a types.d.ts where I declared that zig file path as a module, inside which I added type definitions for the calc function. Now typescript is happy and when I hovered over the calc function, the types are working great as expected. The whole combination looked perfect, but it was still a static prototype and not anything people would be able to use in their projects. I recorded my screen showcasing this scary syntax with black magic happening in the background and even showed when I changed the operation from addition to subtraction, the changes were still reflected. I recorded for both a Zig and a Rust file and posted them on the server again. Soon, Jarred reposted both of the videos on Twitter &lt;a href="https://twitter.com/jarredsumner/status/1681608754067046400"&gt;here&lt;/a&gt; showcasing the power of bun. Everyone in the comments of the tweet went crazy to see something like this even possible.&lt;br&gt;
&lt;a href="https://i.giphy.com/media/aWPGuTlDqq2yc/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/aWPGuTlDqq2yc/giphy.gif" alt="" width="480" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Primeagen commented, &lt;em&gt;"This is super cool. Do you have any articles or anything I can read on this?"&lt;/em&gt;, so I decided to write this article for him :)&lt;/p&gt;

&lt;p&gt;People kept blowing up my discord asking me when I'll release it. I apologize for making them wait but its now out, finally!&lt;/p&gt;

&lt;p&gt;The most difficult part was to make things dynamic because, in that prototype, I had to manually declare the FFI symbol definitions like argument and return types for the calc function and also manually wrote the type definitions too. I wanted things to be automated as much as possible and the user to have full control of every aspect when they would use it in their project. I wanted flexibility which put me into thinking what's the best approach to making this prototype into a real thing people would use in their projects. I experimented with various approaches but all failed in some way which decreased my motivation to work further on this project. I abandoned it for a long time and I also had university stuff going on in between.&lt;/p&gt;

&lt;p&gt;My goal was, that I wanted the users...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;...to add support for any other kind of other language which isn't available by default, easily.&lt;/li&gt;
&lt;li&gt;...to be able to swap implementations with their custom logic.&lt;/li&gt;
&lt;li&gt;...to import any other kind of plugin and not just be restricted to loading other language files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three months later, last week I started from scratch. It was my fourth or fifth attempt at rewriting from scratch. But every time, I started all over again I had experience of the old failed ideas. This final time, I decided to approach this by taking advantage of inheritance, basically classes. Where I split the whole logic into their functions allowing the user to extend and override them essentially swapping the implementations with their custom ones. Took me a week to get everything working as I wanted it to. My most important goals are achieved.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Loader class can be extended by the user and functions can be overridden with custom implementations to customize the behavior.&lt;/li&gt;
&lt;li&gt;Any kind of plugin can be imported through hyperimport.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not to mention but, this idea was also featured on the official Bun 1.0 launch video. &lt;a href="https://youtu.be/BsnCpESUEqM?t=221"&gt;Watch here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Can I use it? Is it on github??"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Absolutely! Check out the &lt;a href="https://github.com/tr1ckydev/hyperimport"&gt;Hyperimport repository&lt;/a&gt; and browse the &lt;a href="https://github.com/tr1ckydev/hyperimport/wiki"&gt;wiki&lt;/a&gt; for a comprehensive documentation with guides.&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://github.com/tr1ckydev/hyperimport/wiki/Importing-a-rust-file"&gt;Importing a rust file&lt;/a&gt;, for a step by step guide on setting up a basic hyperimport project.&lt;/p&gt;

&lt;p&gt;Feel free to join the &lt;a href="https://discord.com/invite/tfBA2z8mbq"&gt;discord server&lt;/a&gt;, if you have any questions.&lt;/p&gt;

&lt;p&gt;If you have come this far, thank you so much for reading the article. The story behind a crazy experimental idea turned into reality. I am really excited and will be looking forward to what mind blowing ideas people can make use of it and push it's limits.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>bunjs</category>
    </item>
  </channel>
</rss>
