fix(play.html): motor înainte de boot — elimină race „motor lipsă" în Brave
Cauză: boot-ul (inflate hash → __runGame()) rula într-un <script> ÎNAINTEA celui care definea window.__runGame. În Brave, await-ul din inflate se rezolva pe microtask înainte ca scriptul motor să fie parsat → __runGame undefined → "Eroare internă: motor lipsă." Fix în generator (campaignShell bootMode='hash'): definește window.__runGame în primul <script>, apoi boot-ul (compressJs + TPL + inflate → MASTER → __runGame()) în al doilea. Ordinea garantează că motorul există când boot-ul rulează — fără injecție dinamică, fără dependență de timing. play.html regenerat din playerHTML(). Test @share actualizat: verifică engine-before-boot, fără text/plain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2068,22 +2068,41 @@ roomReady();
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function campaignShell({ tplJson, masterExpr, titleExpr, nStyles, bootMode }) {
|
function campaignShell({ tplJson, masterExpr, titleExpr, nStyles, bootMode }) {
|
||||||
|
/* bootMode 'hash': motorul se DEFINEȘTE întâi (window.__runGame), boot-ul îl apelează după.
|
||||||
|
* Ordinea garantează că __runGame există când boot-ul rulează — fără injecție dinamică și fără
|
||||||
|
* race de parsare (await-ul din inflate se poate rezolva pe microtask înainte ca un <script>
|
||||||
|
* ulterior să fie parsat; în Brave asta dădea „motor lipsă"). */
|
||||||
const _scriptOpen = bootMode === 'hash'
|
const _scriptOpen = bootMode === 'hash'
|
||||||
? `<script>
|
? `<script>
|
||||||
|
window.__runGame=function(){
|
||||||
|
var MASTER=window.MASTER;`
|
||||||
|
: `<script>
|
||||||
|
var TPL = ${tplJson};
|
||||||
|
var MASTER = ${masterExpr};`;
|
||||||
|
|
||||||
|
/* Închiderea: pentru 'hash' închide funcția __runGame, apoi emite scriptul de boot
|
||||||
|
* (inflate hash → window.MASTER → window.__runGame()). Pentru 'inline' doar închide scriptul. */
|
||||||
|
const _scriptClose = bootMode === 'hash'
|
||||||
|
? `};
|
||||||
|
<\/script>
|
||||||
|
<script>
|
||||||
${SNIP.compressJs}
|
${SNIP.compressJs}
|
||||||
var TPL = ${tplJson};
|
var TPL = ${tplJson};
|
||||||
(async function(){
|
(async function(){
|
||||||
var h=location.hash.slice(1);
|
var h=location.hash.slice(1);
|
||||||
if(!h){document.getElementById('intro-title').textContent='Niciun joc în acest link.';return;}
|
if(!h){document.getElementById('intro-title').textContent='Niciun joc în acest link.';return;}
|
||||||
window.MASTER=JSON.parse(await inflateFromBase64url(h));
|
try { window.MASTER=JSON.parse(await inflateFromBase64url(h)); }
|
||||||
var s=document.createElement('script');s.textContent=document.getElementById('run').textContent;document.body.appendChild(s);
|
catch(e){ document.getElementById('intro-title').textContent='Link invalid sau corupt. Regenerează QR-ul din builder.'; return; }
|
||||||
|
if(typeof window.__runGame!=='function'){document.getElementById('intro-title').textContent='Eroare internă: motor lipsă.';return;}
|
||||||
|
try { window.__runGame(); }
|
||||||
|
catch(e){ document.getElementById('intro-title').textContent='Eroare joc: '+e.message; }
|
||||||
})();
|
})();
|
||||||
<\/script>
|
<\/script>
|
||||||
<script type="text/plain" id="run">
|
</body>
|
||||||
var MASTER=window.MASTER;`
|
</html>`
|
||||||
: `<script>
|
: `<\/script>
|
||||||
var TPL = ${tplJson};
|
</body>
|
||||||
var MASTER = ${masterExpr};`;
|
</html>`;
|
||||||
|
|
||||||
return `<!doctype html>
|
return `<!doctype html>
|
||||||
<html lang="ro">
|
<html lang="ro">
|
||||||
@@ -3108,9 +3127,7 @@ buildDots();
|
|||||||
startTimer(); /* resume → reia ceasul de la deadline-ul absolut salvat */
|
startTimer(); /* resume → reia ceasul de la deadline-ul absolut salvat */
|
||||||
startMusic(); /* resume → reia muzica (T10) */
|
startMusic(); /* resume → reia muzica (T10) */
|
||||||
})();
|
})();
|
||||||
<\/script>
|
${_scriptClose}`;
|
||||||
</body>
|
|
||||||
</html>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function gameCampaign(cfg) {
|
function gameCampaign(cfg) {
|
||||||
|
|||||||
@@ -1695,22 +1695,29 @@ test.describe('Share: link + QR + player @share', () => {
|
|||||||
expect(errors).toHaveLength(0);
|
expect(errors).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('@share playerHTML() genereaza HTML cu inflate + script run + TPL', async ({ page }) => {
|
test('@share playerHTML() genereaza HTML cu inflate + motor inainte de boot + TPL', async ({ page }) => {
|
||||||
const errors = trackErrors(page);
|
const errors = trackErrors(page);
|
||||||
await page.goto(fileURL('escape-builder.html'));
|
await page.goto(fileURL('escape-builder.html'));
|
||||||
const result = await page.evaluate(() => {
|
const result = await page.evaluate(() => {
|
||||||
if (typeof playerHTML !== 'function') return { err: 'playerHTML missing' };
|
if (typeof playerHTML !== 'function') return { err: 'playerHTML missing' };
|
||||||
const html = playerHTML();
|
const html = playerHTML();
|
||||||
|
/* Motorul (window.__runGame) trebuie definit ÎNAINTE ca boot-ul să-l apeleze, ca să nu
|
||||||
|
* existe race de parsare (Brave dădea „motor lipsă" când await-ul din inflate se rezolva
|
||||||
|
* pe microtask înainte ca scriptul motor să fie parsat). */
|
||||||
return {
|
return {
|
||||||
hasInflate: html.includes('inflateFromBase64url'),
|
hasInflate: html.includes('inflateFromBase64url'),
|
||||||
hasRunScript: html.includes('text/plain'),
|
hasRunGame: html.includes('window.__runGame=function'),
|
||||||
|
noLegacyInjection: !html.includes('text/plain'),
|
||||||
|
engineBeforeBoot: html.indexOf('window.__runGame=function') < html.indexOf('inflateFromBase64url(h)'),
|
||||||
hasTPL: html.includes('var TPL'),
|
hasTPL: html.includes('var TPL'),
|
||||||
len: html.length
|
len: html.length
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
expect(result.err, 'error').toBeUndefined();
|
expect(result.err, 'error').toBeUndefined();
|
||||||
expect(result.hasInflate, 'inflate helper').toBe(true);
|
expect(result.hasInflate, 'inflate helper').toBe(true);
|
||||||
expect(result.hasRunScript, 'text/plain run script').toBe(true);
|
expect(result.hasRunGame, 'window.__runGame definit').toBe(true);
|
||||||
|
expect(result.noLegacyInjection, 'fara injectie dinamica text/plain').toBe(true);
|
||||||
|
expect(result.engineBeforeBoot, 'motorul definit inaintea boot-ului').toBe(true);
|
||||||
expect(result.hasTPL, 'var TPL').toBe(true);
|
expect(result.hasTPL, 'var TPL').toBe(true);
|
||||||
expect(result.len).toBeGreaterThan(5000);
|
expect(result.len).toBeGreaterThan(5000);
|
||||||
expect(errors).toHaveLength(0);
|
expect(errors).toHaveLength(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user