mirror of
https://github.com/hanzoai/render.git
synced 2026-10-30 15:04:50 +00:00
A Node 24 process that claims render jobs from Studio's render lane (/v1/studio/render), renders one output, asks the lane where it goes, PUTs it there, and completes the job with the measured result. Five ops: render.html (exact PNG/JPEG/WebP or one-page PDF), render.document (PDF, DOCX, Markdown), render.slides (PPTX with notes, or a 1920x1080 PDF per slide), render.composition (@hanzo/frames), and video.edit (ffmpeg: trim, fit, join, libass captions, overlays, mixed audio). Every page runs in a fresh browser context behind request interception and a per-job egress proxy, which frames' Chrome and Node go through too; ffmpeg opens only local files through a demuxer whitelist. The image is node:24-bookworm-slim with Debian's chromium-headless-shell (amd64 and arm64), ffmpeg and fonts, built for both platforms by hanzoai/ci.
31 lines
1.3 KiB
TypeScript
31 lines
1.3 KiB
TypeScript
import assert from 'node:assert/strict'
|
|
import { mkdtemp, writeFile } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import { setTimeout as sleep } from 'node:timers/promises'
|
|
import { test } from 'node:test'
|
|
import { config } from '../src/engine.ts'
|
|
import { start } from '../src/worker.ts'
|
|
import { fake } from './fake.ts'
|
|
|
|
test('the ServiceAccount token is exchanged at IAM, and again after a 401', async () => {
|
|
const f = await fake()
|
|
const sa = join(await mkdtemp(join(tmpdir(), 'sa-')), 'token')
|
|
await writeFile(sa, 'sa-jwt\n')
|
|
const w = start(config({ HANZO_API: f.url, HANZO_IAM_URL: f.url, HANZO_SA_TOKEN: sa, RENDER_CONCURRENCY: '1' }))
|
|
try {
|
|
while (f.hits.filter((h) => h.path.endsWith('/claim')).length < 2) await sleep(50)
|
|
f.deny = 1
|
|
while (f.calls('token').length < 2) await sleep(50)
|
|
while (f.hits.filter((h) => h.path.endsWith('/claim')).length < 5) await sleep(50)
|
|
} finally {
|
|
await w.stop()
|
|
await f.close()
|
|
}
|
|
const exchange = f.calls('token')[0]
|
|
assert.equal(exchange.headers['content-type'], 'application/x-www-form-urlencoded')
|
|
const lane = f.hits.filter((h) => h.path.startsWith('/v1/studio/render/'))
|
|
assert.equal(lane[0].headers.authorization, 'Bearer iam-0')
|
|
assert.equal(lane.at(-1)!.headers.authorization, 'Bearer iam-1', 'a 401 re-exchanges the token')
|
|
})
|