node-half.spec.ts 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. /** Node half: registers the /api prefix route bridging to the api gateway. */
  2. import { Context } from 'cordis'
  3. import { describe, expect, it } from 'vitest'
  4. import type { IncomingMessage, ServerResponse } from 'node:http'
  5. import type { ApiProxy } from '@deepseek-ai/dsh-host-apiproxy/api'
  6. import type { HttpServerService, WebRoute } from '@deepseek-ai/dsh-host-webserver'
  7. import { API_PATH, apply, inject } from '../src/index.ts'
  8. describe('connection node half', () => {
  9. it('registers the /api prefix route and removes it with the fiber', async () => {
  10. const ctx = new Context()
  11. const routes: WebRoute[] = []
  12. // Structural fake: the plugin only touches register(); the service class
  13. // carries private state a literal cannot (and need not) reproduce.
  14. const httpServer: Pick<HttpServerService, 'register' | 'tapIndex' | 'port'> = {
  15. register(route) {
  16. routes.push(route)
  17. return () => { routes.splice(routes.indexOf(route), 1) }
  18. },
  19. tapIndex: () => () => {},
  20. port: 0,
  21. }
  22. ctx.provide('httpServer', httpServer as HttpServerService)
  23. ctx.provide('apiProxy', {} as unknown as ApiProxy)
  24. const fiber = ctx.plugin({ inject: [...inject], apply })
  25. await fiber.await()
  26. expect(routes).toHaveLength(1)
  27. expect(routes[0]).toMatchObject({ kind: 'prefix', path: API_PATH })
  28. for (const url of ['/api/host.pickDirectory', '/api/host.openPath']) {
  29. let status: number | undefined
  30. let body: unknown
  31. const deniedRequest = {
  32. url,
  33. headers: {
  34. host: 'harness.example', origin: 'http://harness.example', 'sec-fetch-site': 'same-origin',
  35. },
  36. socket: { remoteAddress: '192.168.1.8' },
  37. } as unknown as IncomingMessage
  38. const deniedResponse = {
  39. writeHead(value: number) { status = value; return this },
  40. end(value?: unknown) { body = value; return this },
  41. } as unknown as ServerResponse
  42. await routes[0]!.handler(deniedRequest, deniedResponse)
  43. expect(status).toBe(403)
  44. expect(body).toBe('forbidden')
  45. }
  46. await fiber.dispose()
  47. expect(routes).toHaveLength(0)
  48. })
  49. })