I wrote a JavaScript library in 2012 and published it to npm. Around 2015 I put the project in mothballs and moved on to other things. Several years later I learned that this semi-retired library is the most widely used JavaScript that I’ll ever write.

This is a story about Modelo, a JavaScript library that implements inheritance.

The Origin

I started to program in earnest around 2008. I don’t know that it was a particularly unique time period but I do get occasionally nostalgic. I got to see Ruby on Rails[1] gain a foothold and even offered to donate my time building a RoR stack website for my favorite 2008 US presidential candidate. That offer wasn’t accepted and that candidate didn’t win their party’s primary but those two things are entirely unrelated. I remember the beginnings of the Python 2/3 split[2] and the Django 1.0 release[3]. Python and Django would later end up playing a role in kickstarting my professional career in software. The WWW went 2.0[4] and programming had to adapt to the new, interactive web world.

What really fascinated me, though, was JavaScript. Between 2008 and 2010 I ravenously followed the first open source releases of Node.js[5], the formalization of ECMAScript 5[6], and the onset of npm[7]. To my unmolded mind, the JavaScript ecosystem represented a revolution in how software would be built in the future. I could use the same language to do everything from making my web page dynamic to solving the C10K problem[8]. Some of my first open source collaborations involved working with others on finding the ideal way to make JavaScript code run on both server and client, what we called isomorphic JavaScript at the time[9], before tools like "browserify"[10] and its kin simplified the process. JavaScript felt, to me, like it was becoming something that would change the future of software and I was smitten.

Around this time I was influenced by Douglas Crockford’s[11] writing on "prototypal inheritance"[12] which had evolved into a Node.js built-in called util.inherits that was, in turn, gaining adoption in the browser through polyfills[13]. The introduction to prototypal inheritance was formative for me but the common implementation was lacking. Notably, util.inherits didn’t support multiple inheritance which I needed to implement mix-ins[14]. So I created Modelo.js[15] in 2012, a drop-in replacement for util.inherits that supported multiple inheritance.

The core logic of Modelo didn’t change much over time. The majority of the commits in the repo are related to other libraries that I spun off into separate projects, updating the README and npm configuration, or changing the module’s isomorphic wrapper to keep up with changes in the packaging ecosystem. Modelo was a relatively simple wrapper around some runtime primitives that provided for a specific and mostly personal desire.

I started working for a new company in mid 2013 where the primary language for development was Python. With the professional focus on Python, all of my old JavaScript projects became strictly hobbies for nights and weekends. I tinkered with JavaScript as often as I could and occasionally made patches to Modelo in order to keep up with the still evolving API contract of util.inherits. For me, this was a "labor of love". I enjoyed working on JavaScript related problems and Modelo provided an outlet for me to continue reading, learning, and problem solving in that context.

Over time, the JavaScript inheritance space started to stabilize. ECMAScript 6 promised to introduce classes and, with them, a more mainstream inheritance style. At the same time, my professional work had me investing in deep specialties that didn’t involve JavaScript. At a certain point, I was out of will to continue keeping up with the state of the art of JavaScript. I made my last change to the Modelo code in late 2015.

The Outage

About a month after my last commit in 2015, I received a pull request[16] that improved the npm packaging process by limiting the number of irrelevant files bundled in the final package. It was a one line change and easy to approve. I honestly didn’t think much of it. Someone, somewhere got enough value out of my experimental library to not only use it but contribute their own time to improving it. I merged the change, pushed the new package, and then heard no more from that contributor. This was the last contribution to Modelo until 2018.

Between 2015 and 2018, I seldom even thought of Modelo. It was functionally stable but its utility and unique value were decreasing with time. It was also clear at this point that my professional career was not going to involve JavaScript, at least not the JavaScript that captured my imagination in 2008. Software jobs begat software jobs and I specialized further and further away from my early programming passions.

Then, on January 4th, 2018 I received another pull request to Modelo[17]. The request was to add an MIT license identifier to my npm configuration so that someone’s CI checks, which included license verification, would pass. Again, someone cared enough about my old passion project to invest their time in improving it. I was happy to merge the request but, first, I had to blow the dust off the project.

In three years, some of the test tooling had changed to the point that Modelo’s automated tests and static analysis suites no longer ran or passed. No big deal. I pinned some legacy versions of dependencies to get CI partying like it’s 2015 and all systems were "go" for merging this inconsequential npm metadata patch. I merged the change on Saturday, January 6th, 2018 at 10:30 AM my local time and published the update to npm.

Within 45 minutes I had my first email from someone whose build had broken. 15 minutes after that, people were discussing the same issue in another project[18]. 15 more minutes and there was an open issue for Modelo[19]. Happy weekend, everyone!

Clearly, there was an issue with the package I pushed to npm but I was mostly stunned that I had so many users that a bad deploy was caught within an hour and on a weekend. Real, human people in 2018 were not only using my six year old JavaScript inheritance library but relying on it strongly enough that it was worth disrupting their weekend when it broke. Even to the day that I wrote this article, I was the only person who ever contributed actual code to Modelo. There were no forks of the project on GitHub and it had only six stars. By every metric I knew at the time, my library was firmly placed within the realm of the obscure. So, I took a minute to learn the scope of the issue.

Little did I know that the 2015 pull request I received to minimize the size of the npm package was actually associated with Modelo’s inclusion as a dependency in the Google and Firebase JavaScript SDKs. The 2018 request to update the license identifier was a follow up from someone on a Google team. For several years my strange and arcane side project had silently satisfied some necessary functionality of someone else’s, much more popular project. I don’t recall exactly what tool was available at the time but I ended up using some equivalent of npm-stat.com to peek at usage.

Usage data showing Modelo having roughly zero downloads a day until late 2015. From there, Modelo grows to around 30 thousand downloads a day by the date of the outage.

Admittedly, downloads are a poor proxy for usage because downloads include automated CI jobs and spam library builds. Even so, it’s pretty clear that the library had effectively zero usage until late 2015 to early 2016. Unbeknownst to me, I had become the sole maintainer of a decently used library.

Long story short, the issue was that npm had gone through several major version upgrades in the years between Modelo updates. The key change was that file paths relative to the root could no longer be identified with ./filepath and instead needed to be identified as filepath. That’s it. Some incremental change over several years resulted in the Modelo package being empty rather than containing code because of two characters at the beginning of each file path. Oops.

I fixed the paths, pushed a new build, and everyone involved was able to enjoy what was left of their weekend.

The Password Leak

I resolved the outage and people went back to work. Modelo wasn’t quite done with me yet, though.

Less than a month after the outage, around January 30th, 2018, I got a message on Gchat, or whatever the gmail integrated chat feature was called at the time. The message was from someone I didn’t recognize and contained a single word: "ping".

I was no stranger to talking to strangers on the internet. My early experiences with technology were filled with message boards, MUDs, AOL chat rooms, and the advent of online console gaming. Talking to strangers can be fun but only in a certain context and a random "ping" didn’t seem like anything good to me. I just closed the chat thread and moved on. Don’t poke the bear. Don’t feed the trolls.

It turns out this internet stranger was a bit more persistent than I expected. A day or two later I got an email from the same person titled "Your npm password is present in a public leak (from another site where you reused it)". The body of the email was:

I guess you should change it. And enable 2FA, if possible. The password in question is **************. It gives publish access to modelo package, among others.

The password in the email was partially masked but it showed enough for me to know this wasn’t a joke. Internet stranger now had my full attention[20]. Not only was that password the single factor needed to push malicious code to potentially large numbers of machines via Modelo it was also the single factor needed to access the vast majority of my digital life. I freaked out a little bit.

That was the day I got a password manager, went through my past years of emails identifying accounts to secure, enabled 2FA wherever possible, and ordered some hardware tokens for good measure. Within minutes of updating my npm credentials and establishing 2FA I got the following message from my new friend, the stranger:

Hi! I see that you changed your password (hope that was you).

It was so eerily fast that I assume my new friend had automated monitoring of my account. I sent them a quick "thanks for not pwning me" message and continued on with my new, more secure digital life.

Modelo and the kindness of a stranger completely changed how I think about and secure my digital assets.

The Long Tail Of Legacy

Since 2018, I have received no bug reports, no emails, no contributions, and no messages from friendly internet strangers who have my password regarding Modelo. The Google and Firebase SDKs have moved on to more recent ECMAScript versions or TypeScript. Those changes made Modelo redundant and it’s no longer a direct dependency of any major and contemporary project that I’m aware of. The problem I solved with Modelo more than a decade ago doesn’t exist anymore. Today, Modelo is an antique. Its primary value in today’s world is as a kind of art piece that gives a glimpse into a world that no longer exists.

Personally, I feel that Modelo beginning, thriving, and slowly ending in obscurity is an achievement. For some short period of time, my library assisted in empowering developers to build newer and better things without requiring me to invest a significant amount of time or energy. It "just worked" virtually all of the time. As for me, I didn’t have to deal with the stereotypical burdens or burnout of an open source maintainer. All I had to do was forget about a library that did exactly what it promised and other people used it, likely without even realizing it was a dependency of their project.

I suspect there aren’t many people in the world who directly interacted with Modelo and those who did might not remember. I do wonder if that 2018 outage ruined someone’s weekend enough that they still remember the package name. I don’t feel the weight of responsibility but I empathize with those who felt the urgency to email me on a weekend because of a failing build. Rest assured that I will never again update Modelo or publish a new release.

I find it a bit funny that there continues to be a steady stream of downloads from npm even today.

Usage data showing Modelo usage peaking in 2019, declining steeply as dependent projects convert to TypeScript or ECMAScript 6 classes, and then a small and steady amount of usage that continues through 2024.

Modelo is still out there, silently inheriting object prototypes in someone’s automated tests or builds. I’m fascinated by the idea that someone out there might actually still be building and deploying Modelo in a real system that they or others actually rely on.

I also like to imagine that some of the builds are automated and forgotten. In a display of excess and futility, my library which no longer serves a purpose is used to build an artifact that does nothing and the process is observed by no one. Would that not be a fitting museum in which to display the art of an early JavaScript inheritance library?