mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
feat(web): unify served and preview startup behind a boot-ready seam
The webserver renders a boot-readiness tail after the injection rows and AppWebEntry.run awaits the __DSH_BOOT_READY__ deferred before reading any injected state. Whichever bootstrap applies the injection table settles the deferred - the served renderer resolves it inline, an asynchronous bootstrap installs it ahead of the entry module and settles it with the handshake - so both deployments run one startup chain and a failed handshake surfaces on the boot page instead of proceeding on missing globals.
This commit is contained in:
@@ -45,6 +45,13 @@ export class AppWebEntry {
|
||||
*/
|
||||
async run(): Promise<void> {
|
||||
try {
|
||||
// Boot-readiness gate: whichever bootstrap applies the injection table
|
||||
// settles this deferred once every row has taken effect — the served
|
||||
// index resolves it in the rendered tail, so the await returns on the
|
||||
// next microtask; an asynchronous bootstrap resolves it after its last
|
||||
// row, or rejects it into the failure rendering below. An absent global
|
||||
// means no bootstrap owns the document and there is nothing to wait for.
|
||||
await (globalThis as { __DSH_BOOT_READY__?: { promise: Promise<void> } }).__DSH_BOOT_READY__?.promise
|
||||
const win = globalThis as DshWindow
|
||||
const moduleLoader = win.__ModuleLoader__
|
||||
if (moduleLoader === undefined) {
|
||||
|
||||
@@ -71,10 +71,20 @@ function splice(html: string, at: number, markup: string): string {
|
||||
return `${html.slice(0, at)}${markup}${html.slice(at)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Tail script settling the boot-readiness deferred (`__DSH_BOOT_READY__`):
|
||||
* the client entry awaits its `.promise` before reading any injected state.
|
||||
* Whichever side runs first creates the deferred (`??=`), so a bootstrap that
|
||||
* applies the table asynchronously installs it ahead of the entry module and
|
||||
* settles it after the last row; the served form below creates and resolves
|
||||
* it in one statement, because every row is already in the document text.
|
||||
*/
|
||||
const READY_MARKUP = '<script>(globalThis.__DSH_BOOT_READY__ ??= Promise.withResolvers()).resolve()</script>'
|
||||
|
||||
/**
|
||||
* Render rows into an index.html body: head rows immediately after the
|
||||
* opening head tag, body rows immediately after the opening body tag, each
|
||||
* group in table order.
|
||||
* group in table order, and the boot-readiness tail after the last body row.
|
||||
* @param html - the raw index.html body.
|
||||
* @param rows - the collected injection table.
|
||||
* @returns the html with every row rendered.
|
||||
@@ -87,6 +97,7 @@ export function renderIndexInjections(html: string, rows: readonly IndexInjectio
|
||||
if (rendered.placement === 'head') head += rendered.markup
|
||||
else body += rendered.markup
|
||||
}
|
||||
body += READY_MARKUP
|
||||
let out = html
|
||||
if (head !== '') {
|
||||
const open = /<head(?:\s[^>]*)?>/i.exec(out)
|
||||
|
||||
@@ -241,11 +241,13 @@ describe('real Loader composition', () => {
|
||||
expect(server.renderIndex('<head></head><body></body>')).toContain('window.__Q__=2')
|
||||
untap()
|
||||
|
||||
// Tag-less fragments: head rows prepend, body rows append.
|
||||
// Tag-less fragments: head rows prepend, body rows append, and the
|
||||
// boot-readiness tail lands after the last body row.
|
||||
expect(renderIndexInjections('<main>x</main>', [
|
||||
{ kind: 'script', placement: 'head', text: 'H' },
|
||||
{ kind: 'script', placement: 'body', text: 'B' },
|
||||
])).toBe('<script>H</script><main>x</main><script>B</script>')
|
||||
])).toBe('<script>H</script><main>x</main><script>B</script>'
|
||||
+ '<script>(globalThis.__DSH_BOOT_READY__ ??= Promise.withResolvers()).resolve()</script>')
|
||||
})
|
||||
|
||||
it('fails the fiber when the port is already taken (fail-loud at activation)', { timeout: 60_000 }, async () => {
|
||||
|
||||
Reference in New Issue
Block a user