open.mjs 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. import { spawn } from 'node:child_process'
  2. import { join } from 'node:path'
  3. const handoffProbe = `
  4. const { writeFileSync } = require('node:fs')
  5. const marker = process.argv[1]
  6. const helperPid = Number(process.argv[2])
  7. setTimeout(() => {
  8. let helperAlive = true
  9. if (process.platform === 'win32') {
  10. try {
  11. process.kill(helperPid, 0)
  12. } catch {
  13. helperAlive = false
  14. }
  15. }
  16. if (helperAlive) writeFileSync(marker, '')
  17. }, 50)
  18. `
  19. export default async function open(url) {
  20. if (process.env.BROWSER_OPEN_TEST_FAILURE !== undefined) {
  21. throw new Error(process.env.BROWSER_OPEN_TEST_FAILURE)
  22. }
  23. const exchange = await fetch(url, { redirect: 'manual' })
  24. const setCookie = exchange.headers.get('set-cookie')
  25. const location = exchange.headers.get('location')
  26. if (exchange.status !== 303 || setCookie === null || location === null) {
  27. throw new Error(`browser authentication exchange returned HTTP ${exchange.status}`)
  28. }
  29. const response = await fetch(new URL(location, url), {
  30. headers: { cookie: setCookie.split(';', 1)[0] },
  31. })
  32. const html = await response.text()
  33. console.log(`dsh browser-open: ${JSON.stringify({
  34. url,
  35. status: response.status,
  36. bootManifest: html.includes('__DSH_BOOT__'),
  37. apiKeyPresent: process.env.DEEPSEEK_API_KEY !== undefined,
  38. dshHomePresent: process.env.DSH_HOME !== undefined,
  39. })}`)
  40. // The Windows launcher writes the server-exit marker only while its helper
  41. // remains alive, so the assembled test detects an early helper exit.
  42. const launcher = spawn(process.execPath, [
  43. '--eval', handoffProbe,
  44. '--', join(process.cwd(), `.dsh-browser-open-${process.ppid}`), String(process.pid),
  45. ], { stdio: 'ignore' })
  46. launcher.unref()
  47. return launcher
  48. }