'use strict'; const assert=require('assert/strict'); const fs=require('fs'); const http=require('http'); const {spawnSync}=require('child_process'); const {createRealtimeHub}=require('../realtime-server'); const {renderApacheBridge}=require('../server/apache-bridge'); (async()=>{ const runtime=fs.readFileSync(require.resolve('../runtime-config.js'),'utf8'); const app=fs.readFileSync(require.resolve('../app.js'),'utf8'); const php=fs.readFileSync(require.resolve('../api-bridge.php'),'utf8'); assert.match(runtime,/api-bridge\.php/); assert.match(runtime,/realtimeTransport:'auto'/); assert.match(app,/\/api\/realtime\/connect/); assert.match(app,/\/api\/realtime\/poll/); assert.match(app,/x-linkfield-authorization/); assert.match(app,/wait:bridge\?'0':'20000'/); assert.match(php,/\.linkfield-port/); assert.match(php,/X-LinkField-Authorization/i); assert.doesNotMatch(php,/file_get_contents\('php:\/\/input'\)/); assert.match(php,/php:\/\/temp\/maxmemory:1048576/); assert.match(renderApacheBridge(4312),/api-bridge\.php\?path=\/api\/\$1 \[QSA,L\]/); const phpCheck=spawnSync('php',['-l',require.resolve('../api-bridge.php')],{encoding:'utf8'}); if(!phpCheck.error)assert.equal(phpCheck.status,0,phpCheck.stderr||phpCheck.stdout); let now=1_000_000; const server=http.createServer(); const hub=createRealtimeHub({server,authenticate:async()=>{throw new Error('unused')},getBoardInfo:async boardId=>boardId==='B0'?{solved:false,bounds:{minX:0,minY:0,maxX:1,maxY:1}}:null,now:()=>now}); try{ const first={playerId:'a'.repeat(24),name:'A'}; const second={playerId:'b'.repeat(24),name:'B'}; const a=hub.createPollingClient(first),b=hub.createPollingClient(second); const directClaim=await hub.claimBoard(first,'B0',a.presenceId);assert.equal(directClaim.ok,true);assert.equal(directClaim.claim.playerName,'A'); const deniedClaim=await hub.claimBoard(second,'B0',b.presenceId);assert.equal(deniedClaim.ok,false);assert.equal(deniedClaim.reason,'occupied'); assert.equal(a.messages[0].type,'ready'); assert.equal(b.messages[0].type,'ready'); await hub.handlePollingMessage(first,a.presenceId,{type:'viewport',minX:-10,minY:-10,maxX:10,maxY:10},a.sequence); await hub.handlePollingMessage(second,b.presenceId,{type:'viewport',minX:-10,minY:-10,maxX:10,maxY:10},b.sequence); now+=1000; await hub.handlePollingMessage(first,a.presenceId,{type:'cursor',x:1,y:2,vx:0,vy:0,cursorStyle:'default'},a.sequence); now+=500; await hub.handlePollingMessage(first,a.presenceId,{type:'reaction',id:'poll-r1',emoji:'🤩',style:'classic',x:1,y:2},a.sequence); const events=hub.pollPollingClient(second,b.presenceId,b.sequence); assert(events.messages.some(message=>message.type==='cursor'&&message.name==='A')); assert(events.messages.some(message=>message.type==='reaction'&&message.reaction?.emoji==='🤩')); assert.equal(hub.disconnectPollingClient(first,a.presenceId),true); }finally{hub.close()} console.log('LinkField v48.0 PHP bridge and HTTP realtime polling smoke test passed'); })().catch(error=>{console.error(error);process.exitCode=1});