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
New RFC revision created: 13 Thomas Hunter II r13
New RFC revision created: 12 Thomas Hunter II r12
New RFC revision created: 11 Thomas Hunter II r11
New RFC revision created: 10 Thomas Hunter II r10
New RFC revision created: 9 Thomas Hunter II r9
New RFC revision created: 8 Thomas Hunter II r8
RFC visibility changed from Internal to Public Thomas Hunter II r7
New RFC revision created: 7 Thomas Hunter II r7
RFC status changed from draft to review Thomas Hunter II r6
New RFC revision created: 6 Thomas Hunter II r6
Global Error Handler