Back to Black Site
SOURCE / PINNED RELEASE

Made of little things.

Black Site

Release
666bc7c74ebd…
Author-recorded commit
05e95af79676…
License
LICENSE
Author’s source reference
nostr://npub12lm3rxsva8kfempyjkxupt09e02n3fezurkyadyqfejdc5e0r2kscqty6r/wss%3A%2F%2Fgit.napplet.soy%2F/n-d2225ddc391

Archive hash verified: 1544e072e245c4a8…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

tests/keyboard.test.mjs
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import { runInNewContext } from 'node:vm';
import test from 'node:test';
import ts from 'typescript';

const source = await readFile(new URL('../src/game-keyboard.ts', import.meta.url), 'utf8');
const compiled = ts.transpileModule(source, {
  compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 },
}).outputText;

function fixture({ available = true, fail = false, pending = false } = {}) {
  const window = new EventTarget();
  window.setTimeout = setTimeout;
  const document = new EventTarget();
  const callbacks = new Map();
  const declarations = [];
  const removed = [];
  const invoked = [];
  const held = [];
  const waits = [];
  const api = {
    onAction(id, cb) { callbacks.set(id, cb); return { close() { callbacks.delete(id); } }; },
    registerAction(action) {
      declarations.push(action);
      if (fail) throw new Error('denied');
      if (pending) return new Promise(resolve => waits.push(() => resolve({ actionId: action.id })));
      return Promise.resolve({ actionId: action.id }); // Runtime may leave actions unbound.
    },
    unregisterAction(id) { removed.push(id); },
  };
  const module = { exports: {} };
  runInNewContext(compiled, {
    module, exports: module.exports, window, document, Element: class {}, queueMicrotask,
    console: { warn() {} },
    require(name) { return name === '@napplet/sdk' ? { keys: api, KEYS_DOMAIN: 'keys' } : { runtimeHasDomain: () => available }; },
  });
  const close = module.exports.installGameKeyboard((...args) => held.push(args), code => invoked.push(code), () => held.push(['reset']));
  function key(code, options = {}) {
    const event = new Event('keydown', { cancelable: true });
    Object.assign(event, { code, repeat: false, ctrlKey: false, altKey: false, metaKey: false, ...options });
    if (options.consumed) event.preventDefault();
    window.dispatchEvent(event);
  }
  return { key, close, callbacks, declarations, removed, invoked, held, waits, window, document };
}
const settle = () => new Promise(resolve => setImmediate(resolve));

test('registers safe stable actions; runtime owns actions even when unbound', async () => {
  const f = fixture();
  await settle();
  assert.equal(f.declarations.length, 9);
  assert.ok(f.declarations.every(a => !['Tab', 'Escape'].includes(a.defaultKey)));
  f.key('KeyR');
  assert.deepEqual(f.invoked, []);
  f.callbacks.get('blacksite.reload')();
  await settle();
  assert.deepEqual(f.invoked, ['KeyR']);
  f.key('KeyW', { consumed: true });
  assert.ok(!f.held.some(([code]) => code === 'KeyW'));
  f.key('Escape');
  assert.equal(f.invoked.at(-1), 'Escape');
  f.close();
  assert.equal(f.callbacks.size, 0);
  assert.equal(new Set(f.removed).size, 9);
  f.key('KeyI');
  assert.equal(f.invoked.length, 2);
});

test('missing or denied optional keys retains local shortcuts and movement', async () => {
  for (const settings of [{ available: false }, { fail: true }]) {
    const f = fixture(settings);
    await settle();
    f.key('KeyR');
    f.key('KeyR', { repeat: true });
    f.key('KeyQ', { ctrlKey: true });
    f.key('KeyI', { isComposing: true });
    f.key('KeyW');
    assert.deepEqual(f.invoked, ['KeyR']);
    assert.ok(f.held.some(([code, down]) => code === 'KeyW' && down));
    f.close();
  }
});

test('consumed action fires once and repeat callbacks are ignored', async () => {
  const f = fixture();
  await settle();
  // Model the runtime document capture callback, after our window capture.
  const dispatch = event => {
    event.preventDefault();
    f.callbacks.get('blacksite.reload')();
  };
  f.window.addEventListener('keydown', dispatch);
  f.key('KeyR', { consumed: true });
  await settle();
  f.key('KeyR', { consumed: true, repeat: true });
  await settle();
  assert.deepEqual(f.invoked, ['KeyR']);
  f.close();
});

test('late registration completion after teardown is unregistered', async () => {
  const f = fixture({ pending: true });
  f.close();
  f.waits.forEach(resolve => resolve());
  await settle();
  assert.equal(f.callbacks.size, 0);
  assert.equal(f.removed.length, 18);
});