Stack Builders News

A collection of thoughts and notes by our team


Sebastián Pulido

Clear Nexus Chrome extension in PureScript


In 2003 President G. W. Bush signed a new law named “Controlling the Assault of Non-Solicited Pornography And Marketing (CAN-SPAM) Act of 2003” which is an approach to the growing number of complaints over commercial spam-emails. In this context, a commercial email is "any electronic mail message the primary purpose of which is the commercial advertisement or promotion of a commercial product or service“. Thus, in order to regulate the traffic of commercial email, the US congress determined that all recipients of such a kind of emails must have the right to decline them.

Regarding this, having an automatized system to allow recipients of commercial emails to decide whether or not they want to be sent email from an organization becomes pretty handy, specially for people involved in marketing and sales who are very prone to inadvertently spam their potential clients.

Clear Nexus: a type-safe and functional solution

Clear Nexus is a two-part service: a Chrome extension which communicates to a back-end. It allows you to determine if the owner of an email address has unsubscribed from your organization's commercial emails, which means that sending content to that address would violate the CAN-SPAM law, as well as offering an easy way for recipients to start rejecting emails by letting them join a do-not-spam-me list maintained by the back-end.

But why is this solution type-safe and functional? ...

Here at Stack Builders we deeply appreciate Functional Programming since it is a great alternative for writing composable and modular applications. That’s why when making the technical decisions about which technologies we should bring to implement Clear Nexus we chose two of the heavyweight contenders in this field. On the one hand, we chose Haskell for the back-end since, from our experience as software developers, it has been an amazing tool when it comes to design expressive, and type-safe applications.

But what about the front-end? ...

Well, the native interface for Chrome extension utilities is implemented in -guess what?- vanilla JavaScript. Oh No!... Probably you are the kind of person who has had annoying and terrible experiences with this language, but you are not to blame as it's so dynamically typed that debugging a JavaScript application is such a painful process in which you have to detect all the problems at runtime!

This problem is even more evident when you have to design such effectful programs as those that manipulate the browser’s DOM or which have to handle asynchronous processes.

Fortunately, on JavaScript-land, many people have become aware of these issues and they have come up with different solutions. One of those solutions is PureScript: our second contender in Clear Nexus. PureScript is this tiny language that is pretty much like Haskell, but compiles to easy-to-read-and-reuse JavaScript. This means we can do DOM manipulations, asynchronous operations, AJAX requests and many other common things programmers are used to doing in JavaScript, without leaving type safety and composability behind.

The Technical Background of Clear Nexus Extension: PureScript

Implementation challenges

When designing Clear Nexus there were three main concerns: Querying the DOM of the Gmail’s main page in order to get information of the compose text-area. Handling asynchronous operations with the Chrome-storage API. Handling asynchronous requests to the Clear Nexus back-end.

Basically, Clear Nexus keeps a loop querying the Gmail’s DOM for emails typed in the compose text-area. Once an email is detected, an AJAX request is sent to the back-end and when it answers back, the extension processes the response and determines if the requested email is either subscribed or unsubscribed. After this, the loop starts again and the extension keeps listening to new events in the compose area.

PureScript in action

PureScript has a pretty handy Foreign Function Interface (FFI) which allows you to easily introduce third-party modules from the enormous JavaScript ecosystem. Thus, PureScript is ideal for adding type-safety to JavaScript foreign functions and also, its monadic and I/O features -similar to Haskell’s- make it a great option to handle effectful asynchronous operations in a modular way.

In this fashion, it was possible to approach all aforementioned concerns properly:

  • Where possible the Gmail’s DOM is manipulated with the purescript-dom library, but we found that some operations are still cumbersome to do with PureScript and so they were directly implemented in vanilla JavaScript -for example, the operation to paste the unsubscription link in the compose text-area- and given a type with the FFI. Thus we could make use of browser's built-in functionality and bring it into the PureScript world with type safety.

  • In a similar fashion, the FFI was used to wrap some operations of the Chrome-storage API -for example, in order to store the admin-token in the storage, we wrapped a function which used the Chrome.storage.sync.set operation, and gave it a type inside PureScript. On the other hand, as manipulating the Chrome-storage is effectful, a Chrome effect was specifically defined to add better specificity to the functions manipulating it.

  • The main loop of the application was implemented as a “recursive callback” between two functions which call each other when an asynchronous operation has completed: The first one executes a callback when an email has been detected in the compose text-area. The second operation is the callback itself which performs the request to the back-end and which subsequently performs more asynchronous actions depending on the answer of the back-end. Nonetheless, this callback calls again the first operation to repeat the loop.

In order to handle the complexity described in the third point, two PureScript modules were used: 1) purescript-aff which provides the Aff monad to handle asynchronous callbacks in continuation passing style, which is a step further from promises to handle a pipe of asynchronous actions.2) The module Control.Monad.Eff.Uncurried of the package purescript-eff which allowed us to implement the callback to be called recursively, so that the main loop of the application could be completely implemented as PureScript code without the need of turning to vanilla JavaScript.

So… What’s the matter? Why are we sharing this information with you?

Here at Stack Builders we have a passion for exploring and mastering technologies that promote the best practices and design patterns in the software industry. Also, We believe in the Open Source culture in such a way that we want the software community to join us in our contributions by letting them take part of our public projects and libraries. This is why we share this knowledge with you, so that you start exploring the code base of Clear Nexus Chrome extension and can contribute with good ideas in a way that you can help us enhance this application.

Thus if you are curious about the code base of this extension, take a look at our repo and contribute either by leaving your comments, describing issues or opening your pull requests!

comments powered byDisqus

Do You Have What it Takes To Be a Stack Builder?