js-dojo

8 the realm seam

GOAL

get the HUD's door guard to accept a loot list the mod built, then watch a function the mod wrote run on the host's own array as if no seam were there at all.

CONCEPT

a custom element runs in the host's one realm. An iframe hands the mod a SECOND realm - its own Array, its own Object, its own copy of every built-in. Values cross the seam intact, but identity checks lie: `instanceof` asks whether the HOST's prototype sits on the value's chain, and a mod-built array inherits from the mod's Array.prototype instead.

HINT

two questions that sound alike. `x instanceof Array` asks "did MY Array stamp this?". Array.isArray(x) asks "is this an array?" - no chain walk, no realm in the question.

MIRRORS

the map mod that ships in its own frame. The loot list it hands back is a real array with real items in it, and the HUD still turns the panel away at the door, because the guard is checking whose Array stamped the list rather than what the list is.

Run

node 08-the-realm-seam.cjs

Source

// DOJO · Module 10 / Exercise 8 — the realm seam
// GOAL: get the HUD's door guard to accept a loot list the mod built,
//       then watch a function the mod wrote run on the host's own
//       array as if no seam were there at all.
// CONCEPT: a custom element runs in the host's one realm. An iframe
//       hands the mod a SECOND realm - its own Array, its own Object,
//       its own copy of every built-in. Values cross the seam intact,
//       but identity checks lie: `instanceof` asks whether the HOST's
//       prototype sits on the value's chain, and a mod-built array
//       inherits from the mod's Array.prototype instead.
// HINT: two questions that sound alike. `x instanceof Array` asks
//       "did MY Array stamp this?". Array.isArray(x) asks "is this an
//       array?" - no chain walk, no realm in the question.
// MIRRORS: the map mod that ships in its own frame. The loot list it
//       hands back is a real array with real items in it, and the HUD
//       still turns the panel away at the door, because the guard is
//       checking whose Array stamped the list rather than what the
//       list is.
// Run: node 08-the-realm-seam.cjs

'use strict';
const assert = require('node:assert');
const vm = require('node:vm');

// The mod is a panel somebody else wrote and shipped. On the HUD it
// would load inside a frame of its own; here node:vm builds the same
// seam in plain Node - a second realm with its own built-ins. Nothing
// below is broken code. The mod is a well-behaved neighbour.
const modRealm = vm.createContext({});
const mod = vm.runInContext(
  `({
    loadout: ['blade', 'tonic', 'map'],
    config: { theme: 'dusk' },
    countSlots(list) {
      return Array.isArray(list) ? list.length : -1;
    },
  })`,
  modRealm,
);

const hostLoadout = ['helm', 'rope'];

// --- TODO 1 --------------------------------------------------------
// Three readings the host takes on values the mod built. Two of them
// use `instanceof`, which walks the value's prototype chain hunting
// for the HOST's Array.prototype or Object.prototype. The third asks
// the value what it is and never looks at a chain.
// In place of null, write the three booleans this object really holds.
const seamReadings = {
  arrayInstanceof: mod.loadout instanceof Array,
  objectInstanceof: mod.config instanceof Object,
  isArray: Array.isArray(mod.loadout),
};

const answerSeam = null; // your answer: the same three keys, booleans

assert.deepStrictEqual(
  seamReadings,
  answerSeam,
  'TODO 1 — what does each reading report across the seam?',
);

// --- TODO 2 --------------------------------------------------------
// acceptsLoadout is the HUD's door guard: the host refuses to draw a
// panel whose loot list is not a list. It waves the host's own arrays
// through and turns the mod's away, which is the whole bug report.
// Rewrite the check so it asks the question the guard actually means,
// and keep saying no to things that are not lists.
function acceptsLoadout(value) {
  return value instanceof Array;
}

assert.strictEqual(
  acceptsLoadout(hostLoadout),
  true,
  'TODO 2 — the guard must still accept the host loot list',
);
assert.strictEqual(
  acceptsLoadout(mod.loadout),
  true,
  'TODO 2 — the guard must accept the mod loot list as well',
);
assert.strictEqual(
  acceptsLoadout('blade'),
  false,
  'TODO 2 — the guard must still reject a value that is not a list',
);

// --- TODO 3 --------------------------------------------------------
// Behaviour crosses the seam even where identity does not. countSlots
// was written inside the mod realm, so over here
// `mod.countSlots instanceof Function` is false while
// `typeof mod.countSlots` is still 'function' - and the host is about
// to call it on an array the HOST built. Read countSlots above, decide
// what it sees from its side of the seam, and write the number it
// hands back for hostLoadout.
const slots = mod.countSlots(hostLoadout);

const answerSlots = null; // your answer

assert.strictEqual(
  slots,
  answerSlots,
  'TODO 3 — what does the mod function report for the host list?',
);

console.log('PASS');

Solution