SOURCE / PINNED RELEASE
Made of little things.
Supersonic RC Revive
- Release
- bb8b570f3600…
- Author-recorded commit
- 073e2d2c0e63…
- License
- LICENSE
- Author’s source reference
- nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.shakespeare.diy%2F/SuperSonicRCRevive
Archive hash verified: 857599401cc78951…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import assert from 'node:assert/strict';
import { before, after, test } from 'node:test';
import { createServer } from 'vite';
let server, protocol, OnlineSession, privateAvailable, publicAvailable;
before(async () => {
server = await createServer({ logLevel: 'error', server: { middlewareMode: true }, appType: 'custom', optimizeDeps: { noDiscovery: true, entries: [] } });
protocol = await server.ssrLoadModule('/src/game/onlineProtocol.ts');
({ OnlineSession, privateAvailable, publicAvailable } = await server.ssrLoadModule('/src/game/onlineSession.ts'));
});
after(() => server?.close());
const me = 'a'.repeat(64), peer = 'b'.repeat(64), other = 'c'.repeat(64);
const roomId = '12345678-1234-4234-8234-123456789012', roomId2 = '12345678-1234-4234-8234-123456789013', newRoom = '12345678-1234-4234-8234-123456789099';
const descriptor = { pack: 'd'.repeat(64), level: null, physics: 'ssrc-rapier-v1' };
const roomOf = (over = {}) => ({ ...descriptor, founded: 1000, nonce: '0'.repeat(32), ...over });
const pose = { p: [0,0,40], q: [0,0,0,1], w: Array.from({length:4},()=>[0,0,-5,0,0]) };
const snapshot = (seq, time, x = 0) => ({...pose, type:'car', seq, time, p:[x,0,40]});
const tick = () => new Promise(r => setImmediate(r));
const wait = ms => new Promise(r => setTimeout(r, ms));
test('private rooms need only WebRTC; public rooms also need CVM', () => {
const saved=Object.getOwnPropertyDescriptor(globalThis,'window');
try {
for(const [napplet,priv,pub] of [[undefined,false,false],[{},false,false],[{cvm:{}},false,false],[{webrtc:{}},true,false],[{cvm:{},webrtc:{}},true,true]]) {
Object.defineProperty(globalThis,'window',{configurable:true,value:{napplet}});
assert.equal(privateAvailable(),priv);assert.equal(publicAvailable(),pub);
}
} finally {if(saved)Object.defineProperty(globalThis,'window',saved);else delete globalThis.window;}
});
/** Fake transport: CVM room directory plus one WebRTC session per open. */
function fixture(mode = {kind:'private',code:'ABCDEF'}, {actor = me, rooms = []} = {}) {
const sent = [], calls = [], closed = [], opened = [];
const state = {rooms: rooms.map(r => ({...r, peers:[...r.peers]}))};
let handler, unsubscribed = false;
const snap = r => ({room:r.room, name:r.name, protocol:protocol.ONLINE_PROTOCOL, capacity:8, peers:[...r.peers]});
const io = {
async call(tool, args) {
calls.push([tool,args]);
if (tool === 'soy_session') return {actor};
if (tool === 'soy_room_list') return {rooms: state.rooms.map(snap)};
if (tool === 'soy_room_join') {
const r = state.rooms.find(r => r.room === args.room);
if (!r || r.peers.length >= 8) throw new Error('Room full');
r.peers.push(actor); return snap(r);
}
if (tool === 'soy_room_create') { const r = {room:newRoom, name:args.name, peers:[actor]}; state.rooms.push(r); return snap(r); }
if (tool === 'soy_room_status') return snap(state.rooms.find(r => r.room === args.room));
if (tool === 'soy_room_leave') return {left:true};
throw new Error(`unexpected ${tool}`);
},
async open(request) { opened.push(request); return {session:{id:`rtc${opened.length}`}}; },
async send(id, message) { sent.push([id,message]); },
async close(id) { closed.push(id); },
events(fn) {handler=fn;return {close(){unsubscribed=true;}};},
};
const session = new OnlineSession(descriptor, mode, io, 'test-namespace', 20);
const id = () => `rtc${opened.length}`;
const emit = (from, payload) => handler({type:'message',sessionId:id(),from,payload});
const join = key => handler({type:'peer',sessionId:id(),pubkey:key,state:'joined'});
const leave = key => handler({type:'peer',sessionId:id(),pubkey:key,state:'left'});
const beacons = () => sent.filter(([,m]) => m.type === 'room').map(([,m]) => m);
return {session,io,state,sent,calls,closed,opened,emit,join,leave,beacons,get unsubscribed(){return unsubscribed;}};
}
test('private codes are six unambiguous characters and parse leniently', () => {
const code = protocol.privateCode(b => b.map((_, i) => i * 37));
assert.match(code,/^[A-HJKMNP-Z2-9]{6}$/);
assert.equal(protocol.parsePrivateCode(' abc-def '),'ABCDEF');
assert.equal(protocol.formatCode('ABCDEF'),'ABC-DEF');
assert.equal(protocol.privateRoom('ABCDEF'),'ssrc-private:ABCDEF');
for (const bad of ['','ABCDE','ABCDEFG','ABC-DE1','O0OOOO','ABC_DEF']) assert.throws(()=>protocol.parsePrivateCode(bad));
});
test('asset identity covers pack, custom level and physics version', () => {
assert.equal(protocol.mismatch(descriptor,{...descriptor}),null);
assert.match(protocol.mismatch(descriptor,{...descriptor,pack:'e'.repeat(64)}),/packs differ/);
assert.match(protocol.mismatch(descriptor,{...descriptor,level:'e'.repeat(64)}),/Levels differ/);
assert.match(protocol.mismatch(descriptor,{...descriptor,physics:'next'}),/versions differ/);
});
test('peer payload validation bounds coordinates, quaternions, wheels and room beacons', () => {
assert.ok(protocol.decodeMessage(snapshot(1,50)));
for (const value of [NaN,Infinity,1e8]) assert.equal(protocol.decodeMessage({...snapshot(1,50),p:[value,0,0]}),null);
assert.equal(protocol.decodeMessage({...snapshot(1,50),q:[0,0,0,0]}),null);
assert.equal(protocol.decodeMessage({...snapshot(1,50),w:[]}),null);
assert.equal(protocol.decodeMessage({...snapshot(-1,50)}),null);
assert.ok(protocol.decodeMessage({type:'room',descriptor:roomOf(),count:2}));
for (const bad of [{nonce:'xyz'},{founded:-1},{founded:1.5},{pack:'nope'}]) assert.equal(protocol.decodeMessage({type:'room',descriptor:roomOf(bad),count:2}),null);
assert.equal(protocol.decodeMessage({type:'room',descriptor:roomOf(),count:0}),null);
});
test('the earliest founded room wins, with the nonce breaking ties', () => {
assert.ok(protocol.olderRoom(roomOf({founded:1}),roomOf({founded:2})));
assert.ok(!protocol.olderRoom(roomOf({founded:2}),roomOf({founded:1})));
assert.ok(protocol.olderRoom(roomOf({nonce:'0'.repeat(32)}),roomOf({nonce:'1'.repeat(32)})));
});
test('remote interpolation ignores stale sequences and clocks, handles teleports and expires', () => {
const car = new protocol.RemoteCar();
car.push(snapshot(0,100000,0),100);
car.push(snapshot(1,100050,10),150);
assert.equal(car.sample(225).p[0],5);
assert.equal(car.push(snapshot(0,100100,100),200),false);
assert.equal(car.push(snapshot(2,90000,100),200),false);
car.push(snapshot(3,100150,1000),250);
assert.equal(car.sample(250).p[0],1000);
assert.equal(car.sample(3300),null);
});
test('an empty private room is founded over WebRTC alone, without any CVM call', async () => {
const f = fixture();let ready=0;
f.session.onReady=()=>ready++;
try {
await f.session.start();
assert.deepEqual(f.opened[0].scope,{type:'room',room:'ssrc-private:ABCDEF'});
assert.equal(f.opened[0].protocol,protocol.ONLINE_PROTOCOL);
assert.equal(ready,0);
await wait(40);
assert.equal(ready,1);assert.equal(f.session.lane,0);
assert.match(f.session.status,/Room ABC-DEF · 1\/8/);
f.join(peer);
assert.equal(f.beacons().at(-1).descriptor.pack,descriptor.pack);
f.emit(peer,snapshot(0,1));
assert.equal(f.session.remote.size,0,'cars count only after the peer confirms the room');
f.emit(peer,{type:'room',descriptor:f.session.roomDescriptor,count:2});
f.emit(peer,snapshot(0,1));
assert.equal(f.session.remote.size,1);assert.equal(f.session.players,2);
f.emit(other,snapshot(0,1));
assert.equal(f.session.remote.size,1,'unconnected senders are ignored');
f.emit(peer,{type:'bye'});
assert.equal(f.session.remote.size,0);assert.equal(f.session.players,1);
} finally {await f.session.close();}
assert.equal(f.calls.length,0);assert.ok(f.unsubscribed);assert.deepEqual(f.closed,['rtc1']);
});
test('a private newcomer adopts the room it hears and spawns beside existing players', async () => {
const f = fixture();let ready=0;
f.session.onReady=()=>ready++;
try {
await f.session.start();f.join(peer);
assert.ok(f.sent.some(([,m])=>m.type==='hello'));
f.emit(peer,{type:'room',descriptor:roomOf(),count:3});
assert.equal(ready,1);assert.equal(f.session.lane,3);
assert.deepEqual(f.session.roomDescriptor,roomOf());
await wait(40);
assert.equal(f.session.roomDescriptor.founded,1000,'the founding timer never overrides an adopted room');
} finally {await f.session.close();}
});
test('rooms stop at eight players', async () => {
const f = fixture();let reason='';
f.session.onEnd=r=>reason=r;
await f.session.start();f.join(peer);
f.emit(peer,{type:'room',descriptor:roomOf(),count:8});
assert.match(reason,/full \(8 players\)/);assert.equal(f.session.ready,false);
const g = fixture();let reason2='';
g.session.onEnd=r=>reason2=r;
await g.session.start();g.join(peer);g.emit(peer,{type:'full'});
assert.match(reason2,/full/);
const h = fixture();
try {
await h.session.start();await wait(40);
const peers=Array.from({length:7},(_,i)=>String(i+1).repeat(64));
for(const key of peers){h.join(key);h.emit(key,{type:'room',descriptor:h.session.roomDescriptor,count:2});}
assert.equal(h.session.players,8);
h.join(other);h.emit(other,{type:'hello'});
assert.equal(h.sent.at(-1)[1].type,'full');
} finally {await h.session.close();}
});
test('when two groups founded the same code, everyone joins the older room', async () => {
const f = fixture();let reason='';
f.session.onEnd=r=>reason=r;
try {
await f.session.start();await wait(40);
const mine=f.session.roomDescriptor;
f.join(peer);
const newer={...mine,founded:mine.founded+1};
f.emit(peer,{type:'room',descriptor:newer,count:1});
assert.deepEqual(f.session.roomDescriptor,mine);assert.equal(f.beacons().at(-1).descriptor.founded,mine.founded);
const older=roomOf({founded:2});
f.emit(peer,{type:'room',descriptor:older,count:2});
assert.deepEqual(f.session.roomDescriptor,older);assert.equal(f.session.players,2);
f.join(other);
f.emit(other,{type:'room',descriptor:roomOf({founded:1,pack:'e'.repeat(64)}),count:1});
assert.match(reason,/different game data/);
} finally {await f.session.close();}
});
test('a newcomer loads the room assets once before admission', async () => {
const f=fixture();let resolve,loads=0,ready=0;
const target=roomOf({pack:'e'.repeat(64),level:'f'.repeat(64),packServers:['https://blossom.example']});
f.session.onAssetsRequired=async d=>{loads++;assert.deepEqual(d,target);return new Promise(r=>resolve=r);};
f.session.onReady=()=>ready++;
try {
await f.session.start();f.join(peer);
f.emit(peer,{type:'room',descriptor:target,count:2});f.emit(peer,{type:'room',descriptor:target,count:2});
await wait(40);
assert.equal(loads,1);assert.equal(ready,0);assert.match(f.session.status,/Downloading/);
resolve({...descriptor,pack:target.pack,level:target.level});await tick();
assert.equal(ready,1);assert.equal(f.session.lane,2);assert.equal(f.session.players,2);
assert.equal(f.session.roomDescriptor,target);
} finally {await f.session.close();}
});
test('asset load failure and cancellation never admit the player', async () => {
const f=fixture();let reason='';
f.session.onAssetsRequired=async()=>{throw new Error('Could not download that asset pack');};
f.session.onEnd=text=>reason=text;
await f.session.start();f.join(peer);
f.emit(peer,{type:'room',descriptor:roomOf({pack:'e'.repeat(64)}),count:2});
await tick();
assert.equal(f.session.ready,false);assert.match(reason,/Could not download/);
const g=fixture();let resolve,active;
g.session.onAssetsRequired=async(d,isActive)=>{active=isActive;return new Promise(r=>resolve=r);};
await g.session.start();g.join(peer);
g.emit(peer,{type:'room',descriptor:roomOf({pack:'e'.repeat(64)}),count:2});
await g.session.close();assert.equal(active(),false);
const sent=g.sent.length;resolve({...descriptor,pack:'e'.repeat(64)});await tick();
assert.equal(g.sent.length,sent);assert.equal(g.session.ready,false);
});
test('incompatible physics ends joining before any download', async () => {
const f=fixture();let downloads=0,reason='';
f.session.onAssetsRequired=async()=>{downloads++;return descriptor;};
f.session.onEnd=text=>reason=text;
await f.session.start();f.join(peer);
f.emit(peer,{type:'room',descriptor:roomOf({pack:'e'.repeat(64),physics:'next'}),count:2});
assert.equal(downloads,0);assert.match(reason,/versions differ/);
});
test('profile names are single-line, control-free and short; display name wins', async () => {
const {tagName}=await server.ssrLoadModule('/src/game/onlineNames.ts');
assert.equal(tagName({displayName:' Robert ',name:'rob'}),'Robert');
assert.equal(tagName({displayName:' ',name:'line\nbreak'}),'line break');
assert.equal(tagName({name:'a'.repeat(30)}),'a'.repeat(15)+'…');
assert.equal(tagName({name:'🏎️'.repeat(20)}).length<=32,true);
for (const missing of [null,undefined,{},{name:42},{name:'\u0000'}]) assert.equal(tagName(missing),null);
});
test('beacons share this player\'s Nostr key; other players resolve names once through NAP-COMMON', async () => {
const {ProfileNames}=await server.ssrLoadModule('/src/game/onlineNames.ts');
const nostr='9'.repeat(64),lookups=[];
const f=fixture();
f.session.profile=me;
f.session.names=new ProfileNames(async key=>{lookups.push(key);return key===nostr?{name:'Speedy'}:null;});
try {
await f.session.start();await wait(40);f.join(peer);
assert.equal(f.beacons().at(-1).profile,me);
assert.equal(protocol.decodeMessage({type:'room',descriptor:roomOf(),count:2,profile:'not-hex'}),null);
f.emit(peer,{type:'room',descriptor:f.session.roomDescriptor,count:2,profile:nostr});
assert.equal(f.session.label(peer),'BBBB','the key tag shows until the profile loads');
await tick();
assert.equal(f.session.label(peer),'Speedy');f.session.label(peer);
assert.deepEqual(lookups,[nostr]);
f.join(other);f.emit(other,{type:'room',descriptor:f.session.roomDescriptor,count:3});
assert.equal(f.session.label(other),'CCCC','anonymous players keep their tag');
} finally {await f.session.close();}
const g=fixture();
g.session.names=new ProfileNames(async()=>{throw new Error('common unavailable');});
try {
await g.session.start();await wait(40);g.join(peer);
assert.equal(g.beacons().at(-1).profile,undefined,'guests share no key');
g.emit(peer,{type:'room',descriptor:g.session.roomDescriptor,count:2,profile:'9'.repeat(64)});
g.session.label(peer);await tick();
assert.equal(g.session.label(peer),'BBBB');
} finally {await g.session.close();}
});
test('public play creates a listed eight-player room when none has space', async () => {
const full={room:roomId,name:'Public · x',peers:Array.from({length:8},(_,i)=>String(i+1).repeat(64))};
const f=fixture({kind:'public'},{rooms:[full]});let ready=0;
f.session.onReady=()=>ready++;
try {
await f.session.start();
const create=f.calls.find(([tool])=>tool==='soy_room_create')[1];
assert.deepEqual({capacity:create.capacity,listed:create.listed,protocol:create.protocol},{capacity:8,listed:true,protocol:protocol.ONLINE_PROTOCOL});
assert.equal(create.name,`Public · ${protocol.assetTag(descriptor)}`);
assert.equal(ready,1,'the creator founds immediately');
assert.deepEqual(f.opened[0].scope,{type:'room',room:newRoom});
assert.match(f.session.status,/^Public · 1\/8/);
} finally {await f.session.close();}
assert.ok(f.calls.some(([tool,args])=>tool==='soy_room_leave'&&args.room===newRoom));
});
test('public play prefers rooms with matching assets, then the fullest, and retries a lost seat', async () => {
const tag=protocol.assetTag(descriptor);
const rooms=[{room:roomId,name:'Public · other',peers:[peer,other]},{room:roomId2,name:`Public · ${tag}`,peers:[peer]}];
const f=fixture({kind:'public'},{rooms});
try {
await f.session.start();
assert.equal(f.calls.find(([tool])=>tool==='soy_room_join')[1].room,roomId2);
assert.deepEqual(f.opened[0].scope,{type:'room',room:roomId2});
assert.equal(f.session.ready,false,'joiners wait to hear the room');
} finally {await f.session.close();}
const g=fixture({kind:'public'},{rooms:[{room:roomId,name:'Public · x',peers:[peer]},{room:roomId2,name:'Public · y',peers:[other]}]});
const join=g.io.call.bind(g.io);const attempts=[];
g.io.call=async(tool,args)=>{if(tool==='soy_room_join'){attempts.push(args.room);if(attempts.length===1)throw new Error('Room full');}return join(tool,args);};
try {
await g.session.start();
assert.deepEqual(attempts,[roomId,roomId2]);
assert.equal(g.session.room.room,roomId2);
} finally {await g.session.close();}
});
test('public play lists again when every seat was taken, and when the directory fails', async () => {
const f=fixture({kind:'public'},{rooms:[{room:roomId,name:'Public · x',peers:[peer]}]});
const call=f.io.call.bind(f.io);let lists=0;
f.io.call=async(tool,args)=>{
if(tool==='soy_room_list'&&++lists===2)f.state.rooms.push({room:roomId2,name:'Public · y',peers:[other]});
if(tool==='soy_room_join'&&args.room===roomId)throw new Error('Room full');
return call(tool,args);
};
try {
await f.session.start();
assert.equal(lists,2);assert.equal(f.session.room.room,roomId2);
assert.ok(!f.calls.some(([tool])=>tool==='soy_room_create'));
} finally {await f.session.close();}
const g=fixture({kind:'public'},{rooms:[{room:roomId,name:'Public · x',peers:[peer]}]});
const gcall=g.io.call.bind(g.io);let failed=false;
g.io.call=async(tool,args)=>{if(tool==='soy_room_list'&&!failed){failed=true;throw new Error('Request timed out');}return gcall(tool,args);};
try {
await g.session.start();
assert.equal(g.session.room.room,roomId);
} finally {await g.session.close();}
});
test('a lone public player moves into a room with the same assets; of two lone rooms only one side moves', async () => {
const tag=protocol.assetTag(descriptor);
const f=fixture({kind:'public'});let reason='';
f.session.onEnd=r=>reason=r;
try {
await f.session.start();
assert.equal(f.session.room.room,newRoom);
f.state.rooms.push({room:roomId,name:'Public · other',peers:[peer,other]});
for(let i=0;i<3;++i)await f.session.poll();
assert.equal(f.session.room.room,newRoom,'rooms needing other assets are left alone');
const higher='12345678-1234-4234-8234-123456789999';
f.state.rooms.push({room:higher,name:`Public · ${tag}`,peers:[peer]});
for(let i=0;i<3;++i)await f.session.poll();
assert.equal(f.session.room.room,newRoom,'the lower lone room stays put');
f.state.rooms.push({room:roomId2,name:`Public · ${tag}`,peers:[peer]});
for(let i=0;i<3;++i)await f.session.poll();
assert.equal(f.session.room.room,roomId2);
assert.ok(f.calls.some(([tool,args])=>tool==='soy_room_leave'&&args.room===newRoom));
assert.deepEqual(f.closed,['rtc1']);assert.deepEqual(f.opened[1].scope,{type:'room',room:roomId2});
assert.equal(f.session.ready,true);assert.equal(reason,'');
f.join(peer);f.emit(peer,{type:'room',descriptor:roomOf(),count:2});
assert.equal(f.session.players,2,'the moved player meets the room on its new session');
for(let i=0;i<3;++i)await f.session.poll();
assert.equal(f.opened.length,2,'connected players never move');
} finally {await f.session.close();}
});
test('a public room continues after its creator leaves and admits only current CVM members', async () => {
const f=fixture({kind:'public'},{rooms:[{room:roomId,name:'Public · x',peers:[peer,other]}]});let reason='';
f.session.onEnd=r=>reason=r;
try {
await f.session.start();f.join(peer);f.join(other);
f.emit(peer,{type:'room',descriptor:roomOf(),count:3});
f.emit(other,{type:'room',descriptor:roomOf(),count:3});
f.emit(peer,snapshot(0,0));
assert.equal(f.session.players,3);
f.state.rooms[0].peers=f.state.rooms[0].peers.filter(p=>p!==peer);
await f.session.poll();
assert.equal(reason,'');assert.equal(f.session.remote.size,0);
assert.equal(f.opened.length,1,'membership changes never reopen the mesh');
assert.equal(f.session.players,2);assert.equal(f.session.ready,true);
f.emit(peer,{type:'room',descriptor:roomOf(),count:3});f.emit(peer,snapshot(1,1));
assert.equal(f.session.players,2,'a departed member is not readmitted');assert.equal(f.session.remote.size,0);
const late='e'.repeat(64);
f.join(late);f.emit(late,{type:'room',descriptor:roomOf(),count:3});
assert.equal(f.session.players,2,'unknown peers wait for the next roster');
f.state.rooms[0].peers.push(late);await f.session.poll();
f.emit(late,{type:'room',descriptor:roomOf(),count:3});
assert.equal(f.session.players,3);
} finally {await f.session.close();}
});
test('a transient room renewal failure keeps driving until membership would lapse', async () => {
const f=fixture({kind:'public'});let reason='';
f.session.onEnd=r=>reason=r;
try {
await f.session.start();
const call=f.io.call.bind(f.io);
f.io.call=async(tool,args)=>tool==='soy_room_status'?Promise.reject(new Error('Request timed out')):call(tool,args);
await f.session.poll();
assert.equal(reason,'');assert.equal(f.session.ready,true);
f.io.call=async(tool,args)=>tool==='soy_room_status'?Promise.reject(new Error('Room expired')):call(tool,args);
await f.session.poll();
assert.match(reason,/Room expired/);
} finally {await f.session.close();}
});
test('cancelling an in-flight public room creation leaves the late room without opening RTC', async () => {
const f=fixture({kind:'public'});let resolve;
const call=f.io.call.bind(f.io);
f.io.call=async(tool,args)=>tool==='soy_room_create'?new Promise(r=>resolve=r):call(tool,args);
const pending=f.session.start();
await wait(5);
await f.session.close();
resolve({room:newRoom,protocol:protocol.ONLINE_PROTOCOL,capacity:8,peers:[me]});
await pending;
assert.equal(f.opened.length,0);
assert.ok(f.calls.some(([tool])=>tool==='soy_room_leave'));
});
test('RTC permission denial ends the session and leaves the public room', async () => {
const f=fixture({kind:'public'});let reason='';
f.io.open=async()=>{throw new Error('Peer connections blocked');};
f.session.onEnd=text=>reason=text;
await assert.rejects(f.session.start(),/blocked/);
await tick();
assert.match(reason,/blocked/);assert.ok(f.unsubscribed);
assert.ok(f.calls.some(([tool])=>tool==='soy_room_leave'));
});
test('snapshot sending never queues behind a pending send', async () => {
const f=fixture();
try {
await f.session.start();f.join(peer);f.emit(peer,{type:'room',descriptor:roomOf(),count:2});
let resolve, calls=0;
f.io.send=async()=>{calls++;return new Promise(r=>resolve=r);};
f.session.update(pose,100);
for(let now=150;now<1000;now+=50) f.session.update(pose,now);
assert.equal(calls,1);
resolve();await tick();
f.session.update(pose,1000);assert.equal(calls,2);
resolve();await tick();
f.io.send=async()=>{};
} finally {await f.session.close();}
});
test('a late RTC open after cancellation is immediately closed', async () => {
const f=fixture();let resolve;
f.io.open=()=>new Promise(r=>resolve=r);
const pending=f.session.start();await tick();
await f.session.close();resolve({session:{id:'late'}});await pending;
assert.deepEqual(f.closed,['late']);assert.equal(f.session.ready,false);
});
test('departure cleanup still closes RTC when a send never settles', async () => {
const f=fixture();await f.session.start();f.join(peer);
f.io.send=()=>new Promise(()=>{});
await f.session.close();
assert.deepEqual(f.closed,['rtc1']);assert.ok(f.unsubscribed);
});
test('descriptor download hints accept bounded HTTPS origins only', () => {
assert.ok(protocol.validDescriptor({...descriptor,packServers:['https://blossom.example']}));
for(const packServers of [['http://example.com'],['https://example.com/path'],['https://user:password@example.com'],Array(9).fill('https://example.com'),[42]])
assert.equal(protocol.validDescriptor({...descriptor,packServers}),false);
});
function assetFixture() {
const oldPack=new ArrayBuffer(1),newPack=new ArrayBuffer(2),oldLevel=new ArrayBuffer(3),newLevel=new ArrayBuffer(4);
let pack=oldPack,level=oldLevel;
const downloads=[],installs=[];
const hash=bytes=>bytes===oldPack?descriptor.pack:bytes===newPack?'e'.repeat(64):bytes===oldLevel?'1'.repeat(64):'f'.repeat(64);
const target={...descriptor,pack:hash(newPack),level:hash(newLevel),packServers:['https://pack.example'],levelServers:['https://level.example']};
const io={
descriptor:async()=>({...descriptor,pack:hash(pack),level:level?hash(level):null}),
pack:()=>pack,level:()=>level,
download:async url=>{downloads.push(url);return url.includes(target.pack)?newPack:newLevel;},
installPack:bytes=>{installs.push(bytes);pack=bytes;level=null;},
installLevel:bytes=>{installs.push(bytes);level=bytes;},
isGlb:bytes=>bytes===oldLevel||bytes===newLevel,
};
return {io,target,downloads,installs,oldPack,oldLevel,newPack,newLevel};
}
test('downloads host pack and custom level with hints, verifies hashes and rebuilds once', async () => {
const {loadHostAssets}=await server.ssrLoadModule('/src/game/onlineAssets.ts');
const f=assetFixture();let rebuilds=0;
const result=await loadHostAssets(f.target,()=>true,async()=>{rebuilds++;},f.io);
assert.equal(protocol.mismatch(f.target,result),null);assert.equal(rebuilds,1);
assert.equal(f.io.pack(),f.newPack);assert.equal(f.io.level(),f.newLevel);
assert.ok(f.downloads[0].includes(encodeURIComponent('https://pack.example')));
assert.ok(f.downloads[1].includes(encodeURIComponent('https://level.example')));
});
test('matching bytes are reused and the guest overlay is removed when the host has none', async () => {
const {loadHostAssets}=await server.ssrLoadModule('/src/game/onlineAssets.ts');
const f=assetFixture();const target={...descriptor,level:null};
await loadHostAssets(target,()=>true,async()=>{},f.io);
assert.equal(f.downloads.length,0);assert.equal(f.io.pack(),f.oldPack);assert.equal(f.io.level(),null);
});
test('failed downloads and cancellation before install leave the previous assets untouched', async () => {
const {loadHostAssets}=await server.ssrLoadModule('/src/game/onlineAssets.ts');
for(const cancel of [false,true]) {
const f=assetFixture();let rebuilds=0;
if(!cancel) f.io.download=async()=>{throw new Error('Resource unavailable');};
await assert.rejects(loadHostAssets(f.target,()=>!cancel,async()=>{rebuilds++;},f.io),cancel?/cancelled/:/unavailable/);
assert.equal(f.installs.length,0);assert.equal(rebuilds,0);
if(cancel) assert.equal(f.downloads.length,0);
assert.equal(f.io.pack(),f.oldPack);assert.equal(f.io.level(),f.oldLevel);
}
});
test('hash mismatch, failed rebuild and cancellation during rebuild restore the previous scene', async () => {
const {loadHostAssets}=await server.ssrLoadModule('/src/game/onlineAssets.ts');
for(const failure of ['hash','build','cancel']) {
const f=assetFixture();let active=true,rebuilds=0;
if(failure==='hash') f.target.pack='0'.repeat(64);
const reload=async()=>{rebuilds++;if(rebuilds===1){if(failure==='build')throw new Error('Invalid track');if(failure==='cancel')active=false;}};
await assert.rejects(loadHostAssets(f.target,()=>active,reload,f.io));
assert.equal(f.io.pack(),f.oldPack);assert.equal(f.io.level(),f.oldLevel);
assert.equal(rebuilds,failure==='hash'?1:2);
}
});
test('download provenance retains Blossom hints for the next player', async () => {
const {fetchPackLink,assetServers}=await server.ssrLoadModule('/src/game/assets.ts');
const saved=Object.getOwnPropertyDescriptor(globalThis,'window');
const buffer=new Uint8Array([1,2,3]).buffer;
const hash=[...new Uint8Array(await crypto.subtle.digest('SHA-256',buffer))].map(b=>b.toString(16).padStart(2,'0')).join('');
const requests=[];
const resource={bytes:async(url,options)=>{requests.push({url,options});return new Blob([buffer]);}};
Object.defineProperty(globalThis,'window',{configurable:true,value:{napplet:{resource}}});
try {
const downloaded=await fetchPackLink(`https://pack.example/${hash}.ssrcpack?xs=mirror.example`);
assert.deepEqual(assetServers(downloaded),['https://pack.example','https://mirror.example']);
assert.equal(requests[0].url,`blossom:sha256:${hash}`);
assert.deepEqual(requests[0].options.servers,assetServers(downloaded));
} finally {if(saved)Object.defineProperty(globalThis,'window',saved);else delete globalThis.window;}
});
