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.
/**
* 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) },
});
};
}
