RFC5: Oden: The Server-First, JavaScript-esque Runtime

This document defines a project titled Oden.js (an anagram of Node and Deno). It is intended to be a way to run "JavaScript" on a server but with the following limitations:

  • Only JavaScript features that are beneficial in a server context are retained
  • Many existing features are hidden behind require() calls
  • This is essentially a fork of JavaScript (via V8)
  • This is essentially a fork of Node.js (by modifying APIs)

Node.js API Modifications #

Based on the number of modifications required this would need to be implemented as a "hard fork" of Node.js. I don't think it would be feasable to float patches on top of Node.js.

New Internal Modules #

  • TODO

Mutated Existing Modules #

The following modules are modified and existing globals are added there:

Timers #

const times = require('timers');
timers.queueMicrotask = global.queueMicrotask;
delete global.queueMicrotask;

timers.sleep = ms => new Promise((resolve) => timers.setTimeout(resolve, ms));

Events #

The following JavaScript globals are moved to top level exports of the require('events') object:

global.EventTarget;
global.Event;
global.CloseEvent;
global.CustomEvent;

Crypto #

The following JavaScript globals are moved to top level exports of the require('crypto') object:

global.Crypto;
global.CryptoKey;
global.SubtleCrypto;

File #

The following JavaScript globals are moved to top level exports of the require('file') object:

global.File;

HTTP #

The following JavaScript globals are moved to top level exports of the require('http') object:

global.fetch;
global.FormData;
global.Request;
global.Response;
global.Headers;
global.AbortController;
global.AbortSignal;
global.WebSocket;

URL #

The following JavaScript globals are moved to top level exports of the require('url') object:

global.encodeURI;
global.decodeURI;
global.encodeURIComponent;
global.escape;
global.unescape;
global.decodeURIComponent;

The following JavaScript globals are already on the top level exports of the require('url') object and are therefor simply removed from the global:

delete global.URL;
delete global.URLSearchParams;
delete global.URLPattern;

Removed Globals #

The following globals are removed as they already exist in an internal module:

// redundant with require('process');
global.process;

// redundant with require('timers');
global.setTimeout;
global.clearTimeout;
global.setImmediate;
global.clearImmediate;
global.setInterval;
global.clearInterval;

// redundant with require('perf_hooks');
global.performance;
global.Performance;
global.PerformanceEntry;
global.PerformanceMark;
global.PerformanceMeasure;
global.PerformanceObserver;
global.PerformanceObserverEntryList;
global.PerformanceResourceTiming;

Dropped Functionality #

  • The Buffer class is removed entirely in favor of TypedArray.
  • Either completely remove require() or completely remove import. One of CJS or ESM is fine.

JavaScript & V8 Modifications #

I don't know much about V8 but I think it would also need to be a "hard fork" of V8.

Modified Functionality #

typeof Operator #

Calling typeof null now returns a string value of 'null'.

Object Stringification #

Generally, when objects are stringified they will be converted to JSON:

Object.prototype.toString = function(...args) { return JSON.stringify(this, ...args); };
Set.prototype.toString = function() { return JSON.stringify(Array.from(this)); };
Map.prototype.toString = function() { return JSON.stringify(Object.fromEntries(this)); };

Dropped Functionality #

String Prototype Methods #

The following string prototype methods are removed:

String.prototype.anchor;
String.prototype.big;
String.prototype.blink;
String.prototype.bold;
String.prototype.fixed;
String.prototype.fontcolor;
String.prototype.fontsize;
String.prototype.italics;
String.prototype.link;
String.prototype.small;
String.prototype.strike;
String.prototype.sub;
String.prototype.sup;

btoa and atob #

The btoa and atob global functions are removed however the functionality still exists as string methods:

const _btoa = global.btoa;
const _atob = global.atob;

String.prototype.toBase64 = function() { return _btoa(this); };
String.prototype.fromBase64 = function() { return _atob(this); };

delete global.btoa;
delete global.atob;

History Log

Complete History Log
Operation Instigator Revision When
RFC status changed from review to published Thomas Hunter II r13
An important comment by Thomas Hunter II was dismissed Thomas Hunter II r13
Thomas Hunter II changed their review to abstain Thomas Hunter II r13
Thomas Hunter II added a new important comment Thomas Hunter II r13
Thomas Hunter II changed their review to comment Thomas Hunter II r13
Now being reviewed by Thomas Hunter II Thomas Hunter II r13
No longer being reviewed by Thomas Hunter II Thomas Hunter II r13
Now being reviewed by Thomas Hunter II Thomas Hunter II r13
New RFC revision created: 13 Thomas Hunter II r13
New RFC revision created: 12 Thomas Hunter II r12
Global Error Handler