Back to Black Site Map Editor
SOURCE / PINNED RELEASE

Made of little things.

Black Site Map Editor

Release
32a57733b7e9…
Author-recorded commit
3f54890f542f…
License
LICENSE
Author’s source reference
nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.shakespeare.diy%2F/black-site-map-editor

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

tests/host.test.mjs
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import ts from 'typescript';
import { mapEventTemplate } from '../src/vendor/map-event.mjs';
const map = JSON.parse(
    await readFile(new URL('../src/vendor/outpost.json', import.meta.url), 'utf8'),
);
const viewer = 'a'.repeat(64),
    other = 'b'.repeat(64);
const source = await readFile(new URL('../src/map-host.ts', import.meta.url), 'utf8');
const js = ts
    .transpileModule(source, {
        compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext },
    })
    .outputText.replace(
        /import \{ identity, outbox, resource, storage, upload \} from '@napplet\/sdk';/,
        'const {identity,outbox,resource,storage,upload} = globalThis.__mapHostFixture;',
    )
    .replace(
        "from './model'",
        `from '${new URL('../src/vendor/validate-map.mjs', import.meta.url).href}'`,
    )
    .replace(
        "from './vendor/map-event.mjs'",
        `from '${new URL('../src/vendor/map-event.mjs', import.meta.url).href}'`,
    );
let pubkey = viewer,
    uploads = 0,
    published = [],
    events = [],
    allow = true,
    readBytes;
const drafts = new Map();
globalThis.__mapHostFixture = {
    identity: { getPublicKey: async () => pubkey, onChanged: () => ({ close() {} }) },
    outbox: {
        query: async () => ({ events }),
        publish: async (event) => {
            if (!allow) return { ok: false, error: 'host policy denies kind 35858' };
            const signed = { ...event, pubkey, id: 'c'.repeat(64), sig: 'd'.repeat(128) };
            published.push(signed);
            return { ok: true, event: signed };
        },
    },
    resource: {
        bytes: async (url) => {
            if (url.startsWith('blossom:')) assert.match(url, /^blossom:sha256:[a-f0-9]{64}$/);
            return new Blob([readBytes]);
        },
    },
    storage: {
        setItem: async (k, v) => drafts.set(k, v),
        getItem: async (k) => drafts.get(k) ?? null,
        removeItem: async (k) => drafts.delete(k),
    },
    upload: {
        info: async () => ({ rails: [{ rail: 'blossom', enabled: true }], maxBytes: 10485760 }),
        upload: async (request) => {
            uploads++;
            const bytes = new Uint8Array(await request.data.arrayBuffer());
            assert.equal(request.noTransform, true);
            assert.equal(request.rail, 'blossom');
            return {
                ok: true,
                status: 'complete',
                uploadId: 'one',
                rail: 'blossom',
                sha256: await host.sha256Hex(bytes),
                size: bytes.length,
                url: 'https://blossom.test/' + map.id,
            };
        },
    },
};
const host = await import('data:text/javascript;base64,' + Buffer.from(js).toString('base64'));
test('publish uses native map kind and reuses verified upload after host denial', async () => {
    allow = false;
    events = [];
    await assert.rejects(host.publishMap(map), (error) => {
        assert.equal(error.upload.status, 'complete');
        assert.equal(error.template.kind, 35858);
        return /policy denies/.test(error.message);
    });
    assert.equal(uploads, 1);
    assert.ok(await host.getPendingUpload(viewer, map));
    allow = true;
    const result = await host.publishMap(map);
    assert.equal(uploads, 1);
    assert.equal(result.event.kind, 35858);
    assert.equal(result.metadata.id, map.id);
});
test('loads verified bytes and rejects tampered downloads', async () => {
    readBytes = new TextEncoder().encode(JSON.stringify(map));
    const event = {
        ...mapEventTemplate(map, {
            sha256: await host.sha256Hex(readBytes),
            size: readBytes.length,
            url: 'https://blossom.test/x',
        }),
        pubkey: viewer,
        id: 'c'.repeat(64),
        sig: 'd'.repeat(128),
    };
    events = [];
    const listRecord = {
        event,
        metadata: (await import('../src/vendor/map-event.mjs')).parseMapEvent(event).map,
        relayHints: [],
    };
    assert.deepEqual(await host.loadMap(listRecord), map);
    readBytes = new TextEncoder().encode(JSON.stringify({ ...map, name: 'TAMPERED' }));
    await assert.rejects(host.loadMap(listRecord), /bytes|hash/);
});
test('another author cannot update or delete; drafts are partitioned by viewer', async () => {
    const prior = published[0];
    const parsed = (await import('../src/vendor/map-event.mjs')).parseMapEvent(prior).map;
    pubkey = other;
    await assert.rejects(
        host.publishMap(map, { base: { event: prior, metadata: parsed, relayHints: [] } }),
        /Only the author/,
    );
    await assert.rejects(
        host.deleteMap({ event: prior, metadata: parsed, relayHints: [] }),
        /identity changed/,
    );
    await host.saveDraft(viewer, { map });
    assert.equal(await host.loadDraft(other), null);
    assert.deepEqual((await host.loadDraft(viewer)).map, map);
    pubkey = viewer;
});
test('stale update fails before uploading', async () => {
    const prior = published[0],
        parsed = (await import('../src/vendor/map-event.mjs')).parseMapEvent(prior).map;
    events = [{ event: { ...prior, id: 'e'.repeat(64) } }];
    const before = uploads;
    await assert.rejects(
        host.publishMap(map, { base: { event: prior, metadata: parsed, relayHints: [] } }),
        /changed since/,
    );
    assert.equal(uploads, before);
});

test('malformed stored drafts and mismatched base owners are rejected', async () => {
    drafts.set(`black-site-editor:draft:${viewer}`, '{"map":{}}');
    await assert.rejects(host.loadDraft(viewer), /invalid map/);
    const event = published[0],
        metadata = (await import('../src/vendor/map-event.mjs')).parseMapEvent(event).map;
    drafts.set(
        `black-site-editor:draft:${other}`,
        JSON.stringify({ map, base: { event, metadata, relayHints: [] } }),
    );
    await assert.rejects(host.loadDraft(other), /owner/);
});
test('timestamp saturated discovery reports a blocked cursor', async () => {
    events = Array.from({ length: 2 }, (_, i) => ({
        event: {
            ...published[0],
            id: String(i).repeat(64),
            tags: published[0].tags.map((tag) => (tag[0] === 'd' ? ['d', `map-${i}`] : tag)),
        },
    }));
    const result = await host.discoverMaps({ limit: 2 });
    assert.equal(result.paginationBlocked, true);
});
test('pending upload remains tracked when status observation fails and Retry polls it', async () => {
    events = [];
    allow = true;
    pubkey = viewer;
    const oldUpload = globalThis.__mapHostFixture.upload.upload;
    const changed = { ...map, id: 'pending-map' };
    const bytes = new TextEncoder().encode(JSON.stringify(changed));
    let statusCalls = 0;
    globalThis.__mapHostFixture.upload.upload = async () => {
        uploads++;
        return { ok: true, status: 'uploading', uploadId: 'pending', rail: 'blossom' };
    };
    globalThis.__mapHostFixture.upload.status = async () => {
        statusCalls++;
        if (statusCalls === 1) throw new Error('temporary observation failure');
        return {
            status: 'complete',
            uploadId: 'pending',
            rail: 'blossom',
            sha256: await host.sha256Hex(bytes),
            size: bytes.length,
            url: 'https://blossom.test/file',
        };
    };
    await assert.rejects(host.publishMap(changed), /observation/);
    const before = uploads;
    await host.publishMap(changed);
    assert.equal(uploads, before);
    assert.equal(statusCalls, 2);
    globalThis.__mapHostFixture.upload.upload = oldUpload;
});
test('delete stops when identity switches during current revision lookup', async () => {
    pubkey = viewer;
    const event = published[0],
        metadata = (await import('../src/vendor/map-event.mjs')).parseMapEvent(event).map;
    const originalQuery = globalThis.__mapHostFixture.outbox.query;
    globalThis.__mapHostFixture.outbox.query = async () => {
        pubkey = other;
        return { events: [{ event }] };
    };
    const count = published.length;
    await assert.rejects(host.deleteMap({ event, metadata, relayHints: [] }), /identity changed/);
    assert.equal(published.length, count);
    globalThis.__mapHostFixture.outbox.query = originalQuery;
    pubkey = viewer;
});

test('upload preflight rejects unsupported rail, size, MIME and synchronous missing method without uploading', async () => {
    pubkey = viewer;
    events = [];
    const api = globalThis.__mapHostFixture.upload,
        originalInfo = api.info;
    const changed = { ...map, id: 'preflight-map' },
        before = uploads;
    for (const [info, pattern] of [
        [{ rails: [{ rail: 'nip96', enabled: true }] }, /Blossom/],
        [{ rails: [{ rail: 'blossom', enabled: true }], maxBytes: 1 }, /limits uploads/],
        [
            { rails: [{ rail: 'blossom', enabled: true }], mimeTypes: ['image/png'] },
            /application\/json/,
        ],
    ]) {
        api.info = async () => info;
        await assert.rejects(host.publishMap(changed), pattern);
    }
    api.info = () => {
        throw new Error('upload.info not implemented');
    };
    await assert.rejects(host.publishMap(changed), /not implemented/);
    assert.equal(uploads, before);
    api.info = originalInfo;
});

test('new publication does not require relay reads to prove a map address is unused', async () => {
    const api = globalThis.__mapHostFixture.outbox;
    const original = api.query;
    pubkey = viewer;
    allow = true;
    try {
        for (const response of [
            { events: [], incomplete: true },
            { events: [], error: 'Relay unavailable' },
            new Error('Read denied'),
        ]) {
            api.query = async () => {
                if (response instanceof Error) throw response;
                return response;
            };
            const result = await host.publishMap({ ...map, id: `offline-${published.length}` });
            assert.equal(result.metadata.address, `35858:${viewer}:${result.metadata.id}`);
        }
    } finally {
        api.query = original;
    }
});

test('same d-tag from another player has different coordinates and cannot block publication', async () => {
    const api = globalThis.__mapHostFixture.outbox;
    const original = api.query;
    pubkey = viewer;
    allow = true;
    try {
        api.query = async (filters) => {
            assert.deepEqual(filters[0].authors, [viewer]);
            assert.deepEqual(filters[0]['#d'], [map.id]);
            return { events: [{ event: { ...published[0], pubkey: other } }] };
        };
        const result = await host.publishMap(map);
        assert.equal(result.metadata.address, `35858:${viewer}:${map.id}`);
        assert.notEqual(result.metadata.address, `35858:${other}:${map.id}`);
    } finally {
        api.query = original;
    }
});

test('an observed own-coordinate conflict is protected even when other relay results are incomplete', async () => {
    const api = globalThis.__mapHostFixture.outbox;
    const original = api.query;
    pubkey = viewer;
    const before = uploads;
    try {
        api.query = async () => ({ events: [{ event: published[0] }], incomplete: true });
        await assert.rejects(host.publishMap(map), /at this address under your account/);
        assert.equal(uploads, before);
    } finally {
        api.query = original;
    }
});