doxa-maps/internal/readme-shots-fix.mjs
Doxa Maps e19697673d
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Doxa Maps — the map bundler, 7 production plugins and the Experimental shelf
2026-09-25 20:07:59 +00:00

70 lines
3.6 KiB
JavaScript

#!/usr/bin/env node
// Targeted re-capture: cap1 (vision-card WITH token so it renders, not the token-error state)
// and cap5 (SPA deep-linked to a plugin so a map shows, not "choose a map").
// Retries navigation while concurrent builds churn the tree.
import { chromium } from 'playwright'
import { createServer } from 'node:http'
import { readFile, stat } from 'node:fs/promises'
import { join, extname, resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { TREE_NAME } from './_tree-name.mjs'
const HERE = dirname(fileURLToPath(import.meta.url))
const ROOT = resolve(HERE, '..', 'public')
const OUT = resolve(HERE, '..', 'documentation', 'readme-images')
const TYPES = { '.html':'text/html', '.js':'text/javascript', '.mjs':'text/javascript',
'.json':'application/json', '.css':'text/css', '.webp':'image/webp', '.png':'image/png',
'.svg':'image/svg+xml', '.geojson':'application/json', '.csv':'text/csv', '.woff2':'font/woff2' }
const server = createServer(async (req, res) => {
try { let p = join(ROOT, decodeURIComponent(req.url.split('?')[0]))
if ((await stat(p)).isDirectory()) p = join(p, 'index.html')
res.writeHead(200, { 'content-type': TYPES[extname(p)] || 'application/octet-stream' })
res.end(await readFile(p)) } catch { res.writeHead(404).end('not found') }
})
await new Promise(r => server.listen(0, '127.0.0.1', r))
const BASE = `http://127.0.0.1:${server.address().port}`
let TK = ''
try { const r = await fetch('https://doxa.life/api/maps/token', { signal: AbortSignal.timeout(8000) })
TK = r.ok ? ((await r.json()).token || '') : '' } catch {}
console.log(TK ? `token acquired (${TK.length})` : 'NO token')
const browser = await chromium.launch()
async function tryShot(name, path, { vp = { width: 1440, height: 900 }, wait = 5000, dsf = 2, before = null, waitFor = null, tries = 8 } = {}) {
for (let t = 1; t <= tries; t++) {
const ctx = await browser.newContext({ viewport: vp, deviceScaleFactor: dsf })
const page = await ctx.newPage()
let ok = false
// Insert tk into the QUERY, keeping any #hash fragment LAST (else the route breaks).
const hashAt = path.indexOf('#')
const basePath = hashAt >= 0 ? path.slice(0, hashAt) : path
const frag = hashAt >= 0 ? path.slice(hashAt) : ''
const url = BASE + basePath + (basePath.includes('?') ? '&' : '?') + 'tk=' + encodeURIComponent(TK) + frag
try {
const resp = await page.goto(url, { waitUntil: 'load', timeout: 30000 })
if (resp && resp.status() === 404) throw new Error('404')
if (waitFor) { try { await page.waitForSelector(waitFor, { timeout: 12000 }) } catch {} }
if (before) await before(page)
await page.waitForTimeout(wait)
await page.screenshot({ path: join(OUT, name + '.png') })
ok = true
console.log(' OK', name, `(try ${t})`)
} catch (e) { console.log(' retry', name, t, e.message.split('\n')[0]) }
finally { await ctx.close() }
if (ok) return true
await new Promise(r => setTimeout(r, 4000))
}
console.log(' GAVE UP', name)
return false
}
// cap1: vision-card DEFAULT instance page (TOKEN_FREE=true -> renders the card instantly, no token error).
// Long wait so the aurora backdrop + rotating stat cards fully paint (they animate in).
await tryShot('cap1-single-element', `/${TREE_NAME}/doxa-vision-card/doxa-vision-card/default/index.html`,
{ wait: 9000 })
// cap5: SPA deep-linked to the prayer map instance so a real painted map shows in the right pane.
await tryShot('cap5-doxa-maps-spa', '/index.html#/doxa-simple-map/doxa-simple-map/prayer',
{ wait: 11000, waitFor: '#app' })
await browser.close(); server.close()
console.log('fix done')