Back to Powder Tool V600Billion
SOURCE / PINNED RELEASE

Made of little things.

Powder Tool V600Billion

Release
142767edcab8…
Author-recorded commit
6d92971effd0…
License
LICENSE
Author’s source reference
nostr://npub1fllw8kw0thjj55wds0uugcnp5kej2nfxd36eruq39d56wwz8r44q5q78wj/wss%3A%2F%2Fgit.napplet.soy%2F/powder-toy

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

source/src/server/index.js
/**
 * Answer the game's HTTP traffic in the page.
 *
 * The web build's request manager (upstream src/client/http/requestmanager/
 * Emscripten.cpp) makes its requests on the main thread and streams the
 * Response body. A glue patch (scripts/upstream.mjs) hands them to
 * `Module.nappletFetch` instead of the global fetch, and `createHandler` is
 * that function: requests to the game's servers are answered by
 * src/server/api.js, everything else fails like an unreachable network (the
 * page's own CSP would block it anyway).
 */
import { API_HOST, STATIC_HOST, createApi } from './api.js';

const HOSTS = new Set([API_HOST, STATIC_HOST]);

/** The request body as the game builds it: FormData (text fields and one file) or raw bytes. */
export async function readForm(body) {
  const form = new Map();
  if (!body) return form;
  if (typeof FormData === 'function' && body instanceof FormData) {
    for (const [key, value] of body.entries()) {
      form.set(key, typeof value === 'string' ? value : new Uint8Array(await value.arrayBuffer()));
    }
    return form;
  }
  // Emscripten hands a DataView over its heap, which is a SharedArrayBuffer under threads;
  // TextDecoder refuses shared memory, so copy first.
  const view = body instanceof DataView ? new Uint8Array(body.buffer, body.byteOffset, body.byteLength)
    : body instanceof Uint8Array ? body : new TextEncoder().encode(String(body));
  const raw = new Uint8Array(view.length);
  raw.set(view);
  for (const [key, value] of new URLSearchParams(new TextDecoder().decode(raw))) form.set(key, value);
  return form;
}

export function createHandler(store, options) {
  const handle = createApi(store, options);
  return async (resource, init = {}) => {
    const url = new URL(typeof resource === 'string' ? resource : resource?.url ?? String(resource));
    if (!HOSTS.has(url.hostname)) throw new TypeError('Failed to fetch');
    const result = await handle({ url, method: String(init.method ?? 'GET').toUpperCase(), form: await readForm(init.body) });
    const payload = typeof result.body === 'string' ? new TextEncoder().encode(result.body) : result.body;
    return new Response(payload, {
      status: result.status,
      headers: { 'content-type': result.type, 'content-length': String(payload.length) },
    });
  };
}