msw 2.13.2 → 2.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/cli/init.js +1 -1
  2. package/lib/browser/index.js +252 -72
  3. package/lib/browser/index.js.map +1 -1
  4. package/lib/browser/index.mjs +252 -72
  5. package/lib/browser/index.mjs.map +1 -1
  6. package/lib/core/{HttpResponse-DlRR1D-f.d.mts → HttpResponse-BF4NGRsf.d.mts} +1 -1
  7. package/lib/core/{HttpResponse-CksOMVAa.d.ts → HttpResponse-yukpQS4a.d.ts} +1 -1
  8. package/lib/core/HttpResponse.d.mts +1 -1
  9. package/lib/core/HttpResponse.d.ts +1 -1
  10. package/lib/core/experimental/compat.d.mts +2 -2
  11. package/lib/core/experimental/compat.d.ts +2 -2
  12. package/lib/core/experimental/compat.js +1 -0
  13. package/lib/core/experimental/compat.js.map +1 -1
  14. package/lib/core/experimental/compat.mjs +1 -0
  15. package/lib/core/experimental/compat.mjs.map +1 -1
  16. package/lib/core/experimental/define-network.d.mts +2 -2
  17. package/lib/core/experimental/define-network.d.ts +2 -2
  18. package/lib/core/experimental/define-network.js +4 -0
  19. package/lib/core/experimental/define-network.js.map +1 -1
  20. package/lib/core/experimental/define-network.mjs +6 -0
  21. package/lib/core/experimental/define-network.mjs.map +1 -1
  22. package/lib/core/experimental/frames/http-frame.d.mts +2 -2
  23. package/lib/core/experimental/frames/http-frame.d.ts +2 -2
  24. package/lib/core/experimental/frames/http-frame.js +2 -0
  25. package/lib/core/experimental/frames/http-frame.js.map +1 -1
  26. package/lib/core/experimental/frames/http-frame.mjs +5 -1
  27. package/lib/core/experimental/frames/http-frame.mjs.map +1 -1
  28. package/lib/core/experimental/frames/network-frame.d.mts +2 -2
  29. package/lib/core/experimental/frames/network-frame.d.ts +2 -2
  30. package/lib/core/experimental/frames/websocket-frame.d.mts +2 -2
  31. package/lib/core/experimental/frames/websocket-frame.d.ts +2 -2
  32. package/lib/core/experimental/frames/websocket-frame.js +2 -0
  33. package/lib/core/experimental/frames/websocket-frame.js.map +1 -1
  34. package/lib/core/experimental/frames/websocket-frame.mjs +2 -0
  35. package/lib/core/experimental/frames/websocket-frame.mjs.map +1 -1
  36. package/lib/core/experimental/handlers-controller.d.mts +1 -1
  37. package/lib/core/experimental/handlers-controller.d.ts +1 -1
  38. package/lib/core/experimental/handlers-controller.js +3 -1
  39. package/lib/core/experimental/handlers-controller.js.map +1 -1
  40. package/lib/core/experimental/handlers-controller.mjs +3 -1
  41. package/lib/core/experimental/handlers-controller.mjs.map +1 -1
  42. package/lib/core/experimental/index.d.mts +2 -2
  43. package/lib/core/experimental/index.d.ts +2 -2
  44. package/lib/core/experimental/index.js +0 -1
  45. package/lib/core/experimental/index.js.map +1 -1
  46. package/lib/core/experimental/index.mjs +1 -2
  47. package/lib/core/experimental/index.mjs.map +1 -1
  48. package/lib/core/experimental/on-unhandled-frame.d.mts +2 -2
  49. package/lib/core/experimental/on-unhandled-frame.d.ts +2 -2
  50. package/lib/core/experimental/on-unhandled-frame.js +1 -0
  51. package/lib/core/experimental/on-unhandled-frame.js.map +1 -1
  52. package/lib/core/experimental/on-unhandled-frame.mjs +1 -0
  53. package/lib/core/experimental/on-unhandled-frame.mjs.map +1 -1
  54. package/lib/core/experimental/setup-api.d.mts +1 -1
  55. package/lib/core/experimental/setup-api.d.ts +1 -1
  56. package/lib/core/experimental/setup-api.js +1 -0
  57. package/lib/core/experimental/setup-api.js.map +1 -1
  58. package/lib/core/experimental/setup-api.mjs +1 -0
  59. package/lib/core/experimental/setup-api.mjs.map +1 -1
  60. package/lib/core/experimental/sources/interceptor-source.d.mts +2 -2
  61. package/lib/core/experimental/sources/interceptor-source.d.ts +2 -2
  62. package/lib/core/experimental/sources/interceptor-source.js.map +1 -1
  63. package/lib/core/experimental/sources/interceptor-source.mjs +1 -3
  64. package/lib/core/experimental/sources/interceptor-source.mjs.map +1 -1
  65. package/lib/core/experimental/sources/network-source.d.mts +3 -3
  66. package/lib/core/experimental/sources/network-source.d.ts +3 -3
  67. package/lib/core/experimental/sources/network-source.js +1 -0
  68. package/lib/core/experimental/sources/network-source.js.map +1 -1
  69. package/lib/core/experimental/sources/network-source.mjs +2 -0
  70. package/lib/core/experimental/sources/network-source.mjs.map +1 -1
  71. package/lib/core/getResponse.d.mts +1 -1
  72. package/lib/core/getResponse.d.ts +1 -1
  73. package/lib/core/graphql.d.mts +1 -1
  74. package/lib/core/graphql.d.ts +1 -1
  75. package/lib/core/graphql.js +1 -0
  76. package/lib/core/graphql.js.map +1 -1
  77. package/lib/core/graphql.mjs +2 -0
  78. package/lib/core/graphql.mjs.map +1 -1
  79. package/lib/core/handlers/GraphQLHandler.d.mts +1 -1
  80. package/lib/core/handlers/GraphQLHandler.d.ts +1 -1
  81. package/lib/core/handlers/GraphQLHandler.js +1 -0
  82. package/lib/core/handlers/GraphQLHandler.js.map +1 -1
  83. package/lib/core/handlers/GraphQLHandler.mjs +4 -1
  84. package/lib/core/handlers/GraphQLHandler.mjs.map +1 -1
  85. package/lib/core/handlers/HttpHandler.d.mts +1 -1
  86. package/lib/core/handlers/HttpHandler.d.ts +1 -1
  87. package/lib/core/handlers/HttpHandler.js +1 -0
  88. package/lib/core/handlers/HttpHandler.js.map +1 -1
  89. package/lib/core/handlers/HttpHandler.mjs +1 -0
  90. package/lib/core/handlers/HttpHandler.mjs.map +1 -1
  91. package/lib/core/handlers/RequestHandler.d.mts +1 -1
  92. package/lib/core/handlers/RequestHandler.d.ts +1 -1
  93. package/lib/core/handlers/RequestHandler.js +1 -0
  94. package/lib/core/handlers/RequestHandler.js.map +1 -1
  95. package/lib/core/handlers/RequestHandler.mjs +2 -0
  96. package/lib/core/handlers/RequestHandler.mjs.map +1 -1
  97. package/lib/core/http.d.mts +1 -1
  98. package/lib/core/http.d.ts +1 -1
  99. package/lib/core/http.js +1 -0
  100. package/lib/core/http.js.map +1 -1
  101. package/lib/core/http.mjs +2 -0
  102. package/lib/core/http.mjs.map +1 -1
  103. package/lib/core/index.d.mts +1 -1
  104. package/lib/core/index.d.ts +1 -1
  105. package/lib/core/passthrough.d.mts +1 -1
  106. package/lib/core/passthrough.d.ts +1 -1
  107. package/lib/core/sse.d.mts +4 -18
  108. package/lib/core/sse.d.ts +4 -18
  109. package/lib/core/sse.js +105 -45
  110. package/lib/core/sse.js.map +1 -1
  111. package/lib/core/sse.mjs +105 -45
  112. package/lib/core/sse.mjs.map +1 -1
  113. package/lib/core/utils/HttpResponse/decorators.d.mts +1 -1
  114. package/lib/core/utils/HttpResponse/decorators.d.ts +1 -1
  115. package/lib/core/utils/cookieStore.js.map +1 -1
  116. package/lib/core/utils/cookieStore.mjs.map +1 -1
  117. package/lib/core/utils/executeHandlers.d.mts +1 -1
  118. package/lib/core/utils/executeHandlers.d.ts +1 -1
  119. package/lib/core/utils/executeHandlers.js +1 -0
  120. package/lib/core/utils/executeHandlers.js.map +1 -1
  121. package/lib/core/utils/executeHandlers.mjs +1 -0
  122. package/lib/core/utils/executeHandlers.mjs.map +1 -1
  123. package/lib/core/utils/handleRequest.d.mts +1 -1
  124. package/lib/core/utils/handleRequest.d.ts +1 -1
  125. package/lib/core/utils/handleRequest.js.map +1 -1
  126. package/lib/core/utils/handleRequest.mjs.map +1 -1
  127. package/lib/core/utils/internal/isHandlerKind.d.mts +1 -1
  128. package/lib/core/utils/internal/isHandlerKind.d.ts +1 -1
  129. package/lib/core/utils/internal/parseGraphQLRequest.d.mts +1 -1
  130. package/lib/core/utils/internal/parseGraphQLRequest.d.ts +1 -1
  131. package/lib/core/utils/internal/parseMultipartData.d.mts +1 -1
  132. package/lib/core/utils/internal/parseMultipartData.d.ts +1 -1
  133. package/lib/core/utils/internal/parseMultipartData.js +1 -0
  134. package/lib/core/utils/internal/parseMultipartData.js.map +1 -1
  135. package/lib/core/utils/internal/parseMultipartData.mjs +1 -0
  136. package/lib/core/utils/internal/parseMultipartData.mjs.map +1 -1
  137. package/lib/core/utils/internal/pipeEvents.js +1 -0
  138. package/lib/core/utils/internal/pipeEvents.js.map +1 -1
  139. package/lib/core/utils/internal/pipeEvents.mjs +1 -0
  140. package/lib/core/utils/internal/pipeEvents.mjs.map +1 -1
  141. package/lib/core/utils/internal/requestHandlerUtils.d.mts +1 -1
  142. package/lib/core/utils/internal/requestHandlerUtils.d.ts +1 -1
  143. package/lib/core/utils/internal/requestHandlerUtils.js.map +1 -1
  144. package/lib/core/utils/internal/requestHandlerUtils.mjs.map +1 -1
  145. package/lib/core/ws/WebSocketClientManager.js.map +1 -1
  146. package/lib/core/ws/WebSocketClientManager.mjs.map +1 -1
  147. package/lib/core/ws/WebSocketIndexedDBClientStore.js +1 -0
  148. package/lib/core/ws/WebSocketIndexedDBClientStore.js.map +1 -1
  149. package/lib/core/ws/WebSocketIndexedDBClientStore.mjs +1 -0
  150. package/lib/core/ws/WebSocketIndexedDBClientStore.mjs.map +1 -1
  151. package/lib/core/ws/WebSocketMemoryClientStore.js +1 -0
  152. package/lib/core/ws/WebSocketMemoryClientStore.js.map +1 -1
  153. package/lib/core/ws/WebSocketMemoryClientStore.mjs +1 -0
  154. package/lib/core/ws/WebSocketMemoryClientStore.mjs.map +1 -1
  155. package/lib/core/ws/handleWebSocketEvent.d.mts +1 -1
  156. package/lib/core/ws/handleWebSocketEvent.d.ts +1 -1
  157. package/lib/core/ws/handleWebSocketEvent.js.map +1 -1
  158. package/lib/core/ws/handleWebSocketEvent.mjs.map +1 -1
  159. package/lib/core/ws.js.map +1 -1
  160. package/lib/core/ws.mjs.map +1 -1
  161. package/lib/iife/index.js +6081 -5821
  162. package/lib/iife/index.js.map +1 -1
  163. package/lib/mockServiceWorker.js +1 -1
  164. package/lib/native/index.js.map +1 -1
  165. package/lib/native/index.mjs.map +1 -1
  166. package/lib/node/index.js.map +1 -1
  167. package/lib/node/index.mjs.map +1 -1
  168. package/lib/shims/cookie.js +152 -62
  169. package/lib/shims/cookie.mjs +152 -62
  170. package/package.json +34 -41
  171. package/src/browser/glossary.ts +1 -1
  172. package/src/browser/setup-worker.ts +2 -2
  173. package/src/browser/sources/service-worker-source.ts +125 -28
  174. package/src/browser/utils/deserializeRequest.ts +0 -1
  175. package/src/browser/utils/should-invalidate-worker.test.ts +122 -0
  176. package/src/browser/utils/should-invalidate-worker.ts +13 -0
  177. package/src/browser/utils/workerChannel.ts +43 -21
  178. package/src/core/experimental/define-network.ts +10 -2
  179. package/src/core/experimental/frames/http-frame.test.ts +2 -1
  180. package/src/core/experimental/frames/http-frame.ts +6 -2
  181. package/src/core/experimental/frames/websocket-frame.test.ts +2 -4
  182. package/src/core/experimental/frames/websocket-frame.ts +3 -2
  183. package/src/core/experimental/handlers-controller.ts +1 -1
  184. package/src/core/experimental/index.ts +1 -1
  185. package/src/core/experimental/on-unhandled-frame.test.ts +2 -4
  186. package/src/core/experimental/setup-api.ts +3 -3
  187. package/src/core/experimental/sources/interceptor-source.ts +2 -6
  188. package/src/core/experimental/sources/network-source.ts +1 -1
  189. package/src/core/graphql.ts +8 -8
  190. package/src/core/handlers/GraphQLHandler.test.ts +3 -4
  191. package/src/core/handlers/GraphQLHandler.ts +15 -11
  192. package/src/core/handlers/HttpHandler.test.ts +3 -2
  193. package/src/core/handlers/HttpHandler.ts +7 -7
  194. package/src/core/handlers/RequestHandler.ts +5 -5
  195. package/src/core/http.ts +5 -5
  196. package/src/core/sse.ts +157 -56
  197. package/src/core/utils/cookieStore.ts +1 -1
  198. package/src/core/utils/executeHandlers.ts +2 -4
  199. package/src/core/utils/handleRequest.test.ts +5 -4
  200. package/src/core/utils/handleRequest.ts +3 -3
  201. package/src/core/utils/internal/parseGraphQLRequest.test.ts +2 -4
  202. package/src/core/utils/internal/parseMultipartData.ts +1 -1
  203. package/src/core/utils/internal/pipeEvents.ts +2 -1
  204. package/src/core/utils/internal/requestHandlerUtils.ts +1 -1
  205. package/src/core/utils/request/onUnhandledRequest.test.ts +2 -4
  206. package/src/core/ws/WebSocketClientManager.test.ts +2 -4
  207. package/src/core/ws/WebSocketClientManager.ts +1 -1
  208. package/src/core/ws/WebSocketIndexedDBClientStore.ts +3 -5
  209. package/src/core/ws/WebSocketMemoryClientStore.ts +3 -5
  210. package/src/core/ws/handleWebSocketEvent.ts +3 -3
  211. package/src/core/ws.ts +1 -1
  212. package/src/native/index.ts +2 -2
  213. package/src/node/async-handlers-controller.ts +2 -2
  214. package/src/node/setup-server-common.ts +4 -4
  215. package/src/node/setup-server.ts +2 -2
  216. package/lib/core/{network-frame-usYiHS0K.d.ts → on-unhandled-frame-BBR-P3kV.d.ts} +12 -12
  217. package/lib/core/{network-frame-B7A0ggXE.d.mts → on-unhandled-frame-Cr1KOZ0I.d.mts} +12 -12
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/sse.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { Emitter } from 'strict-event-emitter'\nimport type { ResponseResolver } from './handlers/RequestHandler'\nimport {\n HttpHandler,\n type HttpRequestResolverExtras,\n type HttpRequestParsedResult,\n} from './handlers/HttpHandler'\nimport type { ResponseResolutionContext } from '#core/utils/executeHandlers'\nimport type { Path, PathParams } from './utils/matching/matchRequestUrl'\nimport { delay } from './delay'\nimport { getTimestamp } from './utils/logging/getTimestamp'\nimport { devUtils } from './utils/internal/devUtils'\nimport { colors } from './ws/utils/attachWebSocketLogger'\nimport { toPublicUrl } from './utils/request/toPublicUrl'\n\ntype EventMapConstraint = {\n message?: unknown\n [key: string]: unknown\n [key: symbol | number]: never\n}\n\nexport type ServerSentEventResolverExtras<\n EventMap extends EventMapConstraint,\n Params extends PathParams,\n> = HttpRequestResolverExtras<Params> & {\n client: ServerSentEventClient<EventMap>\n server: ServerSentEventServer\n}\n\nexport type ServerSentEventResolver<\n EventMap extends EventMapConstraint,\n Params extends PathParams,\n> = ResponseResolver<ServerSentEventResolverExtras<EventMap, Params>, any, any>\n\nexport type ServerSentEventRequestHandler = <\n EventMap extends EventMapConstraint = { message: unknown },\n Params extends PathParams<keyof Params> = PathParams,\n RequestPath extends Path = Path,\n>(\n path: RequestPath,\n resolver: ServerSentEventResolver<EventMap, Params>,\n) => HttpHandler\n\nexport type ServerSentEventMessage<\n EventMap extends EventMapConstraint = { message: unknown },\n> =\n | ToEventDiscriminatedUnion<EventMap & { message: unknown }>\n | {\n id?: never\n event?: never\n data?: never\n retry: number\n }\n\n/**\n * Intercept Server-Sent Events (SSE).\n *\n * @example\n * sse('http://localhost:4321', ({ client }) => {\n * client.send({ data: 'hello world' })\n * })\n *\n * @see {@link https://mswjs.io/docs/sse/ Mocking Server-Sent Events}\n * @see {@link https://mswjs.io/docs/api/sse `sse()` API reference}\n */\nexport const sse: ServerSentEventRequestHandler = (path, resolver) => {\n return new ServerSentEventHandler(path, resolver)\n}\n\nconst SSE_RESPONSE_INIT: ResponseInit = {\n headers: {\n 'content-type': 'text/event-stream',\n 'cache-control': 'no-cache',\n connection: 'keep-alive',\n },\n}\n\nclass ServerSentEventHandler<\n EventMap extends EventMapConstraint,\n> extends HttpHandler {\n #emitter: Emitter<ServerSentEventClientEventMap>\n\n constructor(path: Path, resolver: ServerSentEventResolver<EventMap, any>) {\n invariant(\n typeof EventSource !== 'undefined',\n 'Failed to construct a Server-Sent Event handler for path \"%s\": the EventSource API is not supported in this environment',\n path,\n )\n\n super('GET', path, async (info) => {\n const stream = new ReadableStream({\n start: async (controller) => {\n const client = new ServerSentEventClient<EventMap>({\n controller,\n emitter: this.#emitter,\n })\n const server = new ServerSentEventServer({\n request: info.request,\n client,\n })\n\n await resolver({\n ...info,\n client,\n server,\n })\n },\n })\n\n return new Response(stream, SSE_RESPONSE_INIT)\n })\n\n this.#emitter = new Emitter<ServerSentEventClientEventMap>()\n }\n\n async predicate(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n resolutionContext?: ResponseResolutionContext\n }) {\n if (args.request.headers.get('accept') !== 'text/event-stream') {\n return false\n }\n\n const matches = await super.predicate(args)\n\n if (matches && !args.resolutionContext?.quiet) {\n /**\n * @note Log the intercepted request early.\n * Normally, the `this.log()` method is called when the handler returns a response.\n * For SSE, call that method earlier so the logs are in correct order.\n */\n await super.log({\n request: args.request,\n /**\n * @note Construct a placeholder response since SSE response\n * is being streamed and cannot be cloned/consumed for logging.\n */\n response: new Response('[streaming]', SSE_RESPONSE_INIT),\n })\n\n this.#attachClientLogger(args.request, this.#emitter)\n }\n\n return matches\n }\n\n async log(_args: { request: Request; response: Response }): Promise<void> {\n /**\n * @note Skip the default `this.log()` logic so that when this handler is logged\n * upon handling the request, nothing is printed (we log SSE requests early).\n */\n return\n }\n\n #attachClientLogger(\n request: Request,\n emitter: Emitter<ServerSentEventClientEventMap>,\n ): void {\n const publicUrl = toPublicUrl(request.url)\n\n /* eslint-disable no-console */\n emitter.on('message', (payload) => {\n console.groupCollapsed(\n devUtils.formatMessage(\n `${getTimestamp()} SSE %s %c⇣%c ${payload.event}`,\n ),\n publicUrl,\n `color:${colors.mocked}`,\n 'color:inherit',\n )\n console.log(payload.frames)\n console.groupEnd()\n })\n\n emitter.on('error', () => {\n console.groupCollapsed(\n devUtils.formatMessage(`${getTimestamp()} SSE %s %c\\u00D7%c error`),\n publicUrl,\n `color: ${colors.system}`,\n 'color:inherit',\n )\n console.log('Handler:', this)\n console.groupEnd()\n })\n\n emitter.on('close', () => {\n console.groupCollapsed(\n devUtils.formatMessage(`${getTimestamp()} SSE %s %c■%c close`),\n publicUrl,\n `colors:${colors.system}`,\n 'color:inherit',\n )\n console.log('Handler:', this)\n console.groupEnd()\n })\n /* eslint-enable no-console */\n }\n}\n\ntype Values<T> = T[keyof T]\ntype Identity<T> = { [K in keyof T]: T[K] } & unknown\ntype ToEventDiscriminatedUnion<T> = Values<{\n [K in keyof T]: Identity<\n (K extends 'message'\n ? {\n id?: string\n event?: K\n data?: T[K]\n retry?: never\n }\n : {\n id?: string\n event: K\n data?: T[K]\n retry?: never\n }) &\n // Make the `data` field conditionally required through an intersection.\n (undefined extends T[K] ? unknown : { data: unknown })\n >\n}>\n\ntype ServerSentEventClientEventMap = {\n message: [\n payload: {\n id?: string\n event: string\n data?: unknown\n frames: Array<string>\n },\n ]\n error: []\n close: []\n}\n\nclass ServerSentEventClient<\n EventMap extends EventMapConstraint = { message: unknown },\n> {\n #encoder: TextEncoder\n #controller: ReadableStreamDefaultController\n #emitter: Emitter<ServerSentEventClientEventMap>\n\n constructor(args: {\n controller: ReadableStreamDefaultController\n emitter: Emitter<ServerSentEventClientEventMap>\n }) {\n this.#encoder = new TextEncoder()\n this.#controller = args.controller\n this.#emitter = args.emitter\n }\n\n /**\n * Sends the given payload to the intercepted `EventSource`.\n */\n public send(payload: ServerSentEventMessage<EventMap>): void {\n if ('retry' in payload && payload.retry != null) {\n this.#sendRetry(payload.retry)\n return\n }\n\n this.#sendMessage({\n id: payload.id,\n event: payload.event,\n data:\n typeof payload.data === 'object'\n ? JSON.stringify(payload.data)\n : payload.data,\n })\n }\n\n /**\n * Dispatches the given event on the intercepted `EventSource`.\n */\n public dispatchEvent(event: Event) {\n if (event instanceof MessageEvent) {\n /**\n * @note Use the internal send mechanism to skip normalization\n * of the message data (already normalized by the server).\n */\n this.#sendMessage({\n id: event.lastEventId || undefined,\n event: event.type === 'message' ? undefined : event.type,\n data: event.data,\n })\n return\n }\n\n if (event.type === 'error') {\n this.error()\n return\n }\n\n if (event.type === 'close') {\n this.close()\n return\n }\n }\n\n /**\n * Errors the underlying `EventSource`, closing the connection with an error.\n * This is equivalent to aborting the connection and will produce a `TypeError: Failed to fetch`\n * error.\n */\n public error(): void {\n this.#controller.error()\n this.#emitter.emit('error')\n }\n\n /**\n * Closes the underlying `EventSource`, closing the connection.\n */\n public close(): void {\n this.#controller.close()\n this.#emitter.emit('close')\n }\n\n #sendRetry(retry: number): void {\n if (typeof retry === 'number') {\n this.#controller.enqueue(this.#encoder.encode(`retry:${retry}\\n\\n`))\n }\n }\n\n #sendMessage(message: {\n id?: string\n event?: unknown\n data: unknown | undefined\n }): void {\n const frames: Array<string> = []\n\n if (message.id) {\n frames.push(`id:${message.id}`)\n }\n\n if (message.event) {\n frames.push(`event:${message.event.toString()}`)\n }\n\n if (message.data != null) {\n /**\n * Split data on line terminators (LF, CR, or CRLF) and translate them to individual frames.\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream\n */\n for (const line of message.data.toString().split(/\\r\\n|\\r|\\n/)) {\n frames.push(`data:${line}`)\n }\n }\n\n frames.push('', '')\n\n this.#controller.enqueue(this.#encoder.encode(frames.join('\\n')))\n\n this.#emitter.emit('message', {\n id: message.id,\n event: message.event?.toString() || 'message',\n data: message.data,\n frames,\n })\n }\n}\n\nclass ServerSentEventServer {\n #request: Request\n #client: ServerSentEventClient<ServerSentEventClientEventMap>\n\n constructor(args: { request: Request; client: ServerSentEventClient<any> }) {\n this.#request = args.request\n this.#client = args.client\n }\n\n /**\n * Establishes the actual connection for this SSE request\n * and returns the `EventSource` instance.\n */\n public connect(): EventSource {\n const source = new ObservableEventSource(this.#request.url, {\n withCredentials: this.#request.credentials === 'include',\n headers: {\n /**\n * @note Mark this request as passthrough so it doesn't trigger\n * an infinite loop matching against the existing request handler.\n */\n accept: 'msw/passthrough',\n },\n })\n\n source[kOnAnyMessage] = (event) => {\n Object.defineProperties(event, {\n target: {\n value: this,\n enumerable: true,\n writable: true,\n configurable: true,\n },\n })\n\n // Schedule the server-to-client forwarding for the next tick\n // so the user can prevent the message event.\n queueMicrotask(() => {\n if (!event.defaultPrevented) {\n this.#client.dispatchEvent(event)\n }\n })\n }\n\n // Forward stream errors from the actual server to the client.\n source.addEventListener('error', (event) => {\n Object.defineProperties(event, {\n target: {\n value: this,\n enumerable: true,\n writable: true,\n configurable: true,\n },\n })\n\n queueMicrotask(() => {\n // Allow the user to opt-out from this forwarding.\n if (!event.defaultPrevented) {\n this.#client.dispatchEvent(event)\n }\n })\n })\n\n return source\n }\n}\n\ninterface ObservableEventSourceInit extends EventSourceInit {\n headers?: HeadersInit\n}\n\ntype EventHandler<EventType extends Event> = (\n this: EventSource,\n event: EventType,\n) => any\n\nconst kRequest = Symbol('kRequest')\nconst kReconnectionTime = Symbol('kReconnectionTime')\nconst kLastEventId = Symbol('kLastEventId')\nconst kAbortController = Symbol('kAbortController')\nconst kOnOpen = Symbol('kOnOpen')\nconst kOnMessage = Symbol('kOnMessage')\nconst kOnAnyMessage = Symbol('kOnAnyMessage')\nconst kOnError = Symbol('kOnError')\n\nclass ObservableEventSource extends EventTarget implements EventSource {\n static readonly CONNECTING = 0\n static readonly OPEN = 1\n static readonly CLOSED = 2\n\n public readonly CONNECTING = ObservableEventSource.CONNECTING\n public readonly OPEN = ObservableEventSource.OPEN\n public readonly CLOSED = ObservableEventSource.CLOSED\n\n public readyState: number\n public url: string\n public withCredentials: boolean\n\n private [kRequest]: Request\n private [kReconnectionTime]: number\n private [kLastEventId]: string\n private [kAbortController]: AbortController\n private [kOnOpen]: EventHandler<Event> | null = null\n private [kOnMessage]: EventHandler<MessageEvent> | null = null\n private [kOnAnyMessage]: EventHandler<MessageEvent> | null = null\n private [kOnError]: EventHandler<Event> | null = null\n\n constructor(url: string | URL, init?: ObservableEventSourceInit) {\n super()\n\n this.url = new URL(url).href\n this.withCredentials = init?.withCredentials ?? false\n\n this.readyState = this.CONNECTING\n\n // Support custom request init.\n const headers = new Headers(init?.headers || {})\n headers.append('accept', 'text/event-stream')\n\n this[kAbortController] = new AbortController()\n this[kReconnectionTime] = 2000\n this[kLastEventId] = ''\n this[kRequest] = new Request(this.url, {\n method: 'GET',\n headers,\n credentials: this.withCredentials ? 'include' : 'omit',\n signal: this[kAbortController].signal,\n })\n\n this.connect()\n }\n\n get onopen(): EventHandler<Event> | null {\n return this[kOnOpen]\n }\n\n set onopen(handler: EventHandler<Event>) {\n if (this[kOnOpen]) {\n this.removeEventListener('open', this[kOnOpen])\n }\n this[kOnOpen] = handler.bind(this)\n this.addEventListener('open', this[kOnOpen])\n }\n\n get onmessage(): EventHandler<MessageEvent> | null {\n return this[kOnMessage]\n }\n set onmessage(handler: EventHandler<MessageEvent>) {\n if (this[kOnMessage]) {\n this.removeEventListener('message', { handleEvent: this[kOnMessage] })\n }\n this[kOnMessage] = handler.bind(this)\n this.addEventListener('message', { handleEvent: this[kOnMessage] })\n }\n\n get onerror(): EventHandler<Event> | null {\n return this[kOnError]\n }\n set oneerror(handler: EventHandler<Event>) {\n if (this[kOnError]) {\n this.removeEventListener('error', { handleEvent: this[kOnError] })\n }\n this[kOnError] = handler.bind(this)\n this.addEventListener('error', { handleEvent: this[kOnError] })\n }\n\n public addEventListener<K extends keyof EventSourceEventMap>(\n type: K,\n listener: EventHandler<EventSourceEventMap[K]>,\n options?: boolean | AddEventListenerOptions,\n ): void\n public addEventListener(\n type: string,\n listener: EventHandler<MessageEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void\n public addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void\n\n public addEventListener(\n type: string,\n listener: EventHandler<MessageEvent> | EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void {\n super.addEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n )\n }\n\n public removeEventListener<K extends keyof EventSourceEventMap>(\n type: K,\n listener: (this: EventSource, ev: EventSourceEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ): void\n public removeEventListener(\n type: string,\n listener: (this: EventSource, event: MessageEvent) => any,\n options?: boolean | EventListenerOptions,\n ): void\n public removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void\n\n public removeEventListener(\n type: string,\n listener: EventHandler<MessageEvent> | EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void {\n super.removeEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n )\n }\n\n public dispatchEvent(event: Event): boolean {\n return super.dispatchEvent(event)\n }\n\n public close(): void {\n this[kAbortController].abort()\n this.readyState = this.CLOSED\n }\n\n private async connect() {\n await fetch(this[kRequest])\n .then((response) => {\n this.processResponse(response)\n })\n .catch(() => {\n // Fail the connection on request errors instead of\n // throwing a generic \"Failed to fetch\" error.\n this.failConnection()\n })\n }\n\n private processResponse(response: Response): void {\n if (!response.body) {\n this.failConnection()\n return\n }\n\n if (isNetworkError(response)) {\n this.reestablishConnection()\n return\n }\n\n if (\n response.status !== 200 ||\n response.headers.get('content-type') !== 'text/event-stream'\n ) {\n this.failConnection()\n return\n }\n\n this.announceConnection()\n this.interpretResponseBody(response)\n }\n\n private announceConnection(): void {\n queueMicrotask(() => {\n if (this.readyState !== this.CLOSED) {\n this.readyState = this.OPEN\n this.dispatchEvent(new Event('open'))\n }\n })\n }\n\n private interpretResponseBody(response: Response): void {\n const parsingStream = new EventSourceParsingStream({\n message: (message) => {\n if (message.id) {\n this[kLastEventId] = message.id\n }\n\n if (message.retry) {\n this[kReconnectionTime] = message.retry\n }\n\n const messageEvent = new MessageEvent(\n message.event ? message.event : 'message',\n {\n data: message.data,\n origin: this[kRequest].url,\n lastEventId: this[kLastEventId],\n cancelable: true,\n },\n )\n\n this[kOnAnyMessage]?.(messageEvent)\n this.dispatchEvent(messageEvent)\n },\n abort: () => {\n throw new Error('Stream abort is not implemented')\n },\n close: () => {\n this.failConnection()\n },\n })\n\n response\n .body!.pipeTo(parsingStream)\n .then(() => {\n this.processResponseEndOfBody(response)\n })\n .catch(() => {\n this.failConnection()\n })\n }\n\n private processResponseEndOfBody(response: Response): void {\n if (!isNetworkError(response)) {\n this.reestablishConnection()\n }\n }\n\n private async reestablishConnection(): Promise<void> {\n queueMicrotask(() => {\n if (this.readyState === this.CLOSED) {\n return\n }\n\n this.readyState = this.CONNECTING\n this.dispatchEvent(new Event('error'))\n })\n\n await delay(this[kReconnectionTime])\n\n queueMicrotask(async () => {\n if (this.readyState !== this.CONNECTING) {\n return\n }\n\n if (this[kLastEventId] !== '') {\n this[kRequest].headers.set('last-event-id', this[kLastEventId])\n }\n\n await this.connect()\n })\n }\n\n private failConnection(): void {\n queueMicrotask(() => {\n if (this.readyState !== this.CLOSED) {\n this.readyState = this.CLOSED\n this.dispatchEvent(new Event('error'))\n }\n })\n }\n}\n\n/**\n * Checks if the given `Response` instance is a network error.\n * @see https://fetch.spec.whatwg.org/#concept-network-error\n */\nfunction isNetworkError(response: Response): boolean {\n return (\n response.type === 'error' &&\n response.status === 0 &&\n response.statusText === '' &&\n Array.from(response.headers.entries()).length === 0 &&\n response.body === null\n )\n}\n\nconst enum ControlCharacters {\n NewLine = 10,\n CarriageReturn = 13,\n Space = 32,\n Colon = 58,\n}\n\ninterface EventSourceMessage {\n id?: string\n event?: string\n data?: string\n retry?: number\n}\n\nclass EventSourceParsingStream extends WritableStream {\n private decoder: TextDecoder\n\n private buffer?: Uint8Array\n private position: number\n private fieldLength?: number\n private discardTrailingNewline = false\n\n private message: EventSourceMessage = {\n id: undefined,\n event: undefined,\n data: undefined,\n retry: undefined,\n }\n\n constructor(\n private underlyingSink: {\n message: (message: EventSourceMessage) => void\n abort?: (reason: any) => void\n close?: () => void\n },\n ) {\n super({\n write: (chunk) => {\n this.processResponseBodyChunk(chunk)\n },\n abort: (reason) => {\n this.underlyingSink.abort?.(reason)\n },\n close: () => {\n this.underlyingSink.close?.()\n },\n })\n\n this.decoder = new TextDecoder()\n this.position = 0\n }\n\n private resetMessage(): void {\n this.message = {\n id: undefined,\n event: undefined,\n data: undefined,\n retry: undefined,\n }\n }\n\n private processResponseBodyChunk(chunk: Uint8Array): void {\n if (this.buffer == null) {\n this.buffer = chunk\n this.position = 0\n this.fieldLength = -1\n } else {\n const nextBuffer = new Uint8Array(this.buffer.length + chunk.length)\n nextBuffer.set(this.buffer)\n nextBuffer.set(chunk, this.buffer.length)\n this.buffer = nextBuffer\n }\n\n const bufferLength = this.buffer.length\n let lineStart = 0\n\n while (this.position < bufferLength) {\n if (this.discardTrailingNewline) {\n if (this.buffer[this.position] === ControlCharacters.NewLine) {\n lineStart = ++this.position\n }\n\n this.discardTrailingNewline = false\n }\n\n let lineEnd = -1\n\n for (; this.position < bufferLength && lineEnd === -1; ++this.position) {\n switch (this.buffer[this.position]) {\n case ControlCharacters.Colon: {\n if (this.fieldLength === -1) {\n this.fieldLength = this.position - lineStart\n }\n break\n }\n\n case ControlCharacters.CarriageReturn: {\n this.discardTrailingNewline = true\n break\n }\n\n case ControlCharacters.NewLine: {\n lineEnd = this.position\n break\n }\n }\n }\n\n if (lineEnd === -1) {\n break\n }\n\n this.processLine(\n this.buffer.subarray(lineStart, lineEnd),\n this.fieldLength!,\n )\n\n lineStart = this.position\n this.fieldLength = -1\n }\n\n if (lineStart === bufferLength) {\n this.buffer = undefined\n } else if (lineStart !== 0) {\n this.buffer = this.buffer.subarray(lineStart)\n this.position -= lineStart\n }\n }\n\n private processLine(line: Uint8Array, fieldLength: number): void {\n // New line indicates the end of the message. Dispatch it.\n if (line.length === 0) {\n // Prevent dispatching the message if the data is an empty string.\n // That is a no-op per spec.\n if (this.message.data === undefined) {\n this.message.event = undefined\n return\n }\n\n this.underlyingSink.message(this.message)\n this.resetMessage()\n return\n }\n\n // Otherwise, keep accumulating message fields until the new line.\n if (fieldLength > 0) {\n const field = this.decoder.decode(line.subarray(0, fieldLength))\n const valueOffset =\n fieldLength +\n (line[fieldLength + 1] === ControlCharacters.Space ? 2 : 1)\n const value = this.decoder.decode(line.subarray(valueOffset))\n\n switch (field) {\n case 'data': {\n this.message.data = this.message.data\n ? this.message.data + '\\n' + value\n : value\n break\n }\n\n case 'event': {\n this.message.event = value\n break\n }\n\n case 'id': {\n this.message.id = value\n break\n }\n\n case 'retry': {\n const retry = parseInt(value, 10)\n\n if (!isNaN(retry)) {\n this.message.retry = retry\n }\n break\n }\n }\n }\n }\n}\n"],"mappings":"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","names":["ControlCharacters"]}
1
+ {"version":3,"sources":["../../src/core/sse.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { Emitter } from 'strict-event-emitter'\nimport type { ResponseResolver } from './handlers/RequestHandler'\nimport {\n HttpHandler,\n type HttpRequestResolverExtras,\n type HttpRequestParsedResult,\n} from './handlers/HttpHandler'\nimport type { ResponseResolutionContext } from '#core/utils/executeHandlers'\nimport type { Path, PathParams } from './utils/matching/matchRequestUrl'\nimport { delay } from './delay'\nimport { getTimestamp } from './utils/logging/getTimestamp'\nimport { devUtils } from './utils/internal/devUtils'\nimport { colors } from './ws/utils/attachWebSocketLogger'\nimport { toPublicUrl } from './utils/request/toPublicUrl'\n\ntype EventMapConstraint = {\n message?: unknown\n [key: string]: unknown\n [key: symbol | number]: never\n}\n\nexport type ServerSentEventResolverExtras<\n EventMap extends EventMapConstraint,\n Params extends PathParams,\n> = HttpRequestResolverExtras<Params> & {\n client: ServerSentEventClient<EventMap>\n server: ServerSentEventServer\n}\n\nexport type ServerSentEventResolver<\n EventMap extends EventMapConstraint,\n Params extends PathParams,\n> = ResponseResolver<ServerSentEventResolverExtras<EventMap, Params>, any, any>\n\nexport type ServerSentEventRequestHandler = <\n EventMap extends EventMapConstraint = { message: unknown },\n Params extends PathParams<keyof Params> = PathParams,\n RequestPath extends Path = Path,\n>(\n path: RequestPath,\n resolver: ServerSentEventResolver<EventMap, Params>,\n) => HttpHandler\n\nexport type ServerSentEventMessage<\n EventMap extends EventMapConstraint = { message: unknown },\n> =\n | ToEventDiscriminatedUnion<EventMap & { message: unknown }>\n | {\n id?: never\n event?: never\n data?: never\n retry: number\n }\n\n/**\n * Intercept Server-Sent Events (SSE).\n *\n * @example\n * sse('http://localhost:4321', ({ client }) => {\n * client.send({ data: 'hello world' })\n * })\n *\n * @see {@link https://mswjs.io/docs/sse/ Mocking Server-Sent Events}\n * @see {@link https://mswjs.io/docs/api/sse `sse()` API reference}\n */\nexport const sse: ServerSentEventRequestHandler = (path, resolver) => {\n return new ServerSentEventHandler(path, resolver)\n}\n\nconst SSE_RESPONSE_INIT: ResponseInit = {\n headers: {\n 'content-type': 'text/event-stream',\n 'cache-control': 'no-cache',\n connection: 'keep-alive',\n },\n}\n\nclass ServerSentEventHandler<\n EventMap extends EventMapConstraint,\n> extends HttpHandler {\n #emitter: Emitter<ServerSentEventClientEventMap>\n\n constructor(path: Path, resolver: ServerSentEventResolver<EventMap, any>) {\n invariant(\n typeof EventSource !== 'undefined',\n 'Failed to construct a Server-Sent Event handler for path \"%s\": the EventSource API is not supported in this environment',\n path,\n )\n\n super('GET', path, async (info) => {\n const { client, server, response } = createEventStream<EventMap>(\n info.request,\n )\n\n client[kClientEmitter] = this.#emitter\n\n await resolver({\n ...info,\n client,\n server,\n })\n\n return response\n })\n\n this.#emitter = new Emitter<ServerSentEventClientEventMap>()\n }\n\n async predicate(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n resolutionContext?: ResponseResolutionContext\n }) {\n if (args.request.headers.get('accept') !== 'text/event-stream') {\n return false\n }\n\n const matches = await super.predicate(args)\n\n if (matches && !args.resolutionContext?.quiet) {\n /**\n * @note Log the intercepted request early.\n * Normally, the `this.log()` method is called when the handler returns a response.\n * For SSE, call that method earlier so the logs are in correct order.\n */\n await super.log({\n request: args.request,\n /**\n * @note Construct a placeholder response since SSE response\n * is being streamed and cannot be cloned/consumed for logging.\n */\n response: new Response('[streaming]', SSE_RESPONSE_INIT),\n })\n\n this.#attachClientLogger(args.request, this.#emitter)\n }\n\n return matches\n }\n\n async log(_args: { request: Request; response: Response }): Promise<void> {\n /**\n * @note Skip the default `this.log()` logic so that when this handler is logged\n * upon handling the request, nothing is printed (we log SSE requests early).\n */\n return\n }\n\n #attachClientLogger(\n request: Request,\n emitter: Emitter<ServerSentEventClientEventMap>,\n ): void {\n const publicUrl = toPublicUrl(request.url)\n\n /* eslint-disable no-console */\n emitter.on('message', (payload) => {\n console.groupCollapsed(\n devUtils.formatMessage(\n `${getTimestamp()} SSE %s %c⇣%c ${payload.event}`,\n ),\n publicUrl,\n `color:${colors.mocked}`,\n 'color:inherit',\n )\n console.log(payload.frames)\n console.groupEnd()\n })\n\n emitter.on('error', () => {\n console.groupCollapsed(\n devUtils.formatMessage(`${getTimestamp()} SSE %s %c\\u00D7%c error`),\n publicUrl,\n `color: ${colors.system}`,\n 'color:inherit',\n )\n console.log('Handler:', this)\n console.groupEnd()\n })\n\n emitter.on('close', () => {\n console.groupCollapsed(\n devUtils.formatMessage(`${getTimestamp()} SSE %s %c■%c close`),\n publicUrl,\n `colors:${colors.system}`,\n 'color:inherit',\n )\n console.log('Handler:', this)\n console.groupEnd()\n })\n /* eslint-enable no-console */\n }\n}\n\ntype Values<T> = T[keyof T]\ntype Identity<T> = { [K in keyof T]: T[K] } & unknown\ntype ToEventDiscriminatedUnion<T> = Values<{\n [K in keyof T]: Identity<\n (K extends 'message'\n ? {\n id?: string\n event?: K\n data?: T[K]\n retry?: never\n }\n : {\n id?: string\n event: K\n data?: T[K]\n retry?: never\n }) &\n // Make the `data` field conditionally required through an intersection.\n (undefined extends T[K] ? unknown : { data: unknown })\n >\n}>\n\ntype ServerSentEventClientEventMap = {\n message: [payload: EventStreamMessage]\n error: []\n close: []\n}\n\nconst kClientEmitter = Symbol.for('kClientEmitter')\n\nclass ServerSentEventClient<\n EventMap extends EventMapConstraint = { message: unknown },\n> {\n private [kClientEmitter]?: Emitter<ServerSentEventClientEventMap>\n\n #encoder: TextEncoder\n #writer: WritableStreamDefaultWriter\n\n constructor(writable: WritableStream) {\n this.#encoder = new TextEncoder()\n this.#writer = writable.getWriter()\n }\n\n /**\n * Sends the given payload to the intercepted `EventSource`.\n */\n public send(payload: ServerSentEventMessage<EventMap>): void {\n if ('retry' in payload && payload.retry != null) {\n this.#sendRetry(payload.retry)\n return\n }\n\n this.#sendMessage({\n id: payload.id,\n event: payload.event,\n data:\n typeof payload.data === 'object'\n ? JSON.stringify(payload.data)\n : payload.data,\n })\n }\n\n /**\n * Dispatches the given event on the intercepted `EventSource`.\n */\n public dispatchEvent(event: Event) {\n if (event instanceof MessageEvent) {\n /**\n * @note Use the internal send mechanism to skip normalization\n * of the message data (already normalized by the server).\n */\n this.#sendMessage({\n id: event.lastEventId || undefined,\n event: event.type === 'message' ? undefined : event.type,\n data: event.data,\n })\n return\n }\n\n if (event.type === 'error') {\n this.error()\n return\n }\n\n if (event.type === 'close') {\n this.close()\n return\n }\n }\n\n /**\n * Errors the underlying `EventSource`, closing the connection with an error.\n * This is equivalent to aborting the connection and will produce a `TypeError: Failed to fetch`\n * error.\n */\n public error(): void {\n this.#writer.abort().catch((error) => {\n console.error(error)\n devUtils.error(\n 'Failed to abort server-side EventSource. Please see the original error above.',\n )\n })\n this[kClientEmitter]?.emit('error')\n }\n\n /**\n * Closes the underlying `EventSource`, closing the connection.\n */\n public close(): void {\n this.#writer.close().catch((error) => {\n console.error(error)\n devUtils.error(\n 'Failed to close server-side EventSource. Please see the original error above.',\n )\n })\n this[kClientEmitter]?.emit('close')\n }\n\n #sendRetry(retry: number): void {\n this.#writer\n .write(this.#encoder.encode(`retry:${retry}\\n\\n`))\n .catch((error) => {\n console.error(error)\n devUtils.error(\n 'Failed to send a retry packet to server-side EventSource. Please see the original error above.',\n )\n })\n }\n\n #sendMessage(message: {\n id?: string\n event?: unknown\n data: unknown | undefined\n }): void {\n const frames: Array<string> = []\n\n if (message.id) {\n frames.push(`id:${message.id}`)\n }\n\n if (message.event) {\n frames.push(`event:${message.event.toString()}`)\n }\n\n if (message.data != null) {\n /**\n * Split data on line terminators (LF, CR, or CRLF) and translate them to individual frames.\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream\n */\n for (const line of message.data.toString().split(/\\r\\n|\\r|\\n/)) {\n frames.push(`data:${line}`)\n }\n }\n\n frames.push('', '')\n\n this.#writer\n .write(this.#encoder.encode(frames.join('\\n')))\n .catch((error) => {\n console.error(error)\n devUtils.error(\n 'Failed to send a message to server-side EventSource. Please see the original error above.',\n )\n })\n\n this[kClientEmitter]?.emit('message', {\n id: message.id,\n event: message.event?.toString() || 'message',\n data: message.data,\n frames,\n })\n }\n}\n\nclass ServerSentEventServer {\n #request: Request\n #client: ServerSentEventClient<ServerSentEventClientEventMap>\n\n constructor(args: { request: Request; client: ServerSentEventClient<any> }) {\n this.#request = args.request\n this.#client = args.client\n }\n\n /**\n * Establishes the actual connection for this SSE request\n * and returns the `EventSource` instance.\n */\n public connect(): EventSource {\n const source = new ObservableEventSource(this.#request.url, {\n withCredentials: this.#request.credentials === 'include',\n headers: {\n /**\n * @note Mark this request as passthrough so it doesn't trigger\n * an infinite loop matching against the existing request handler.\n */\n accept: 'msw/passthrough',\n },\n signal: this.#request.signal,\n })\n\n source[kOnAnyMessage] = (event) => {\n Object.defineProperties(event, {\n target: {\n value: this,\n enumerable: true,\n writable: true,\n configurable: true,\n },\n })\n\n // Schedule the server-to-client forwarding for the next tick\n // so the user can prevent the message event.\n queueMicrotask(() => {\n if (!event.defaultPrevented) {\n this.#client.dispatchEvent(event)\n }\n })\n }\n\n // Forward stream errors from the actual server to the client.\n source.addEventListener('error', (event) => {\n Object.defineProperties(event, {\n target: {\n value: this,\n enumerable: true,\n writable: true,\n configurable: true,\n },\n })\n\n queueMicrotask(() => {\n // Allow the user to opt-out from this forwarding.\n if (!event.defaultPrevented) {\n this.#client.dispatchEvent(event)\n }\n })\n })\n\n return source\n }\n}\n\ninterface ObservableEventSourceInit extends EventSourceInit {\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\ntype EventHandler<EventType extends Event> = (\n this: EventSource,\n event: EventType,\n) => any\n\nconst kRequest = Symbol('kRequest')\nconst kReconnectionTime = Symbol('kReconnectionTime')\nconst kLastEventId = Symbol('kLastEventId')\nconst kAbortController = Symbol('kAbortController')\nconst kOnOpen = Symbol('kOnOpen')\nconst kOnMessage = Symbol('kOnMessage')\nconst kOnAnyMessage = Symbol('kOnAnyMessage')\nconst kOnError = Symbol('kOnError')\n\nclass ObservableEventSource extends EventTarget implements EventSource {\n static readonly CONNECTING = 0\n static readonly OPEN = 1\n static readonly CLOSED = 2\n\n public readonly CONNECTING = ObservableEventSource.CONNECTING\n public readonly OPEN = ObservableEventSource.OPEN\n public readonly CLOSED = ObservableEventSource.CLOSED\n\n public readyState: number\n public url: string\n public withCredentials: boolean\n\n private [kRequest]: Request\n private [kReconnectionTime]: number\n private [kLastEventId]: string\n private [kAbortController]: AbortController\n private [kOnOpen]: EventHandler<Event> | null = null\n private [kOnMessage]: EventHandler<MessageEvent> | null = null\n private [kOnAnyMessage]: EventHandler<MessageEvent> | null = null\n private [kOnError]: EventHandler<Event> | null = null\n\n constructor(url: string | URL, init?: ObservableEventSourceInit) {\n super()\n\n this.url = new URL(url).href\n this.withCredentials = init?.withCredentials ?? false\n\n this.readyState = this.CONNECTING\n\n // Support custom request init.\n const headers = new Headers(init?.headers || {})\n headers.append('accept', 'text/event-stream')\n\n this[kAbortController] = new AbortController()\n this[kReconnectionTime] = 2000\n this[kLastEventId] = ''\n this[kRequest] = new Request(this.url, {\n method: 'GET',\n headers,\n credentials: this.withCredentials ? 'include' : 'omit',\n signal: this[kAbortController].signal,\n })\n\n if (init?.signal) {\n if (init.signal.aborted) {\n this.close()\n return\n }\n\n init.signal.addEventListener('abort', () => this.close(), {\n once: true,\n signal: this[kAbortController].signal,\n })\n }\n\n this.connect()\n }\n\n get onopen(): EventHandler<Event> | null {\n return this[kOnOpen]\n }\n\n set onopen(handler: EventHandler<Event>) {\n if (this[kOnOpen]) {\n this.removeEventListener('open', this[kOnOpen])\n }\n this[kOnOpen] = handler.bind(this)\n this.addEventListener('open', this[kOnOpen])\n }\n\n get onmessage(): EventHandler<MessageEvent> | null {\n return this[kOnMessage]\n }\n set onmessage(handler: EventHandler<MessageEvent>) {\n if (this[kOnMessage]) {\n this.removeEventListener('message', { handleEvent: this[kOnMessage] })\n }\n this[kOnMessage] = handler.bind(this)\n this.addEventListener('message', { handleEvent: this[kOnMessage] })\n }\n\n get onerror(): EventHandler<Event> | null {\n return this[kOnError]\n }\n set onerror(handler: EventHandler<Event>) {\n if (this[kOnError]) {\n this.removeEventListener('error', { handleEvent: this[kOnError] })\n }\n this[kOnError] = handler.bind(this)\n this.addEventListener('error', { handleEvent: this[kOnError] })\n }\n\n public addEventListener<K extends keyof EventSourceEventMap>(\n type: K,\n listener: EventHandler<EventSourceEventMap[K]>,\n options?: boolean | AddEventListenerOptions,\n ): void\n public addEventListener(\n type: string,\n listener: EventHandler<MessageEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void\n public addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void\n\n public addEventListener(\n type: string,\n listener: EventHandler<MessageEvent> | EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void {\n super.addEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n )\n }\n\n public removeEventListener<K extends keyof EventSourceEventMap>(\n type: K,\n listener: (this: EventSource, ev: EventSourceEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ): void\n public removeEventListener(\n type: string,\n listener: (this: EventSource, event: MessageEvent) => any,\n options?: boolean | EventListenerOptions,\n ): void\n public removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void\n\n public removeEventListener(\n type: string,\n listener: EventHandler<MessageEvent> | EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void {\n super.removeEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n )\n }\n\n public dispatchEvent(event: Event): boolean {\n return super.dispatchEvent(event)\n }\n\n public close(): void {\n this[kAbortController].abort()\n this.readyState = this.CLOSED\n }\n\n private async connect() {\n await fetch(this[kRequest])\n .then((response) => {\n this.processResponse(response)\n })\n .catch(() => {\n // Fail the connection on request errors instead of\n // throwing a generic \"Failed to fetch\" error.\n this.failConnection()\n })\n }\n\n private processResponse(response: Response): void {\n if (!response.body) {\n this.failConnection()\n return\n }\n\n if (isNetworkError(response)) {\n this.reestablishConnection()\n return\n }\n\n if (\n response.status !== 200 ||\n response.headers.get('content-type') !== 'text/event-stream'\n ) {\n this.failConnection()\n return\n }\n\n this.announceConnection()\n this.interpretResponseBody(response)\n }\n\n private announceConnection(): void {\n queueMicrotask(() => {\n if (this.readyState !== this.CLOSED) {\n this.readyState = this.OPEN\n this.dispatchEvent(new Event('open'))\n }\n })\n }\n\n private interpretResponseBody(response: Response): void {\n const parsingStream = new EventSourceParsingStream({\n message: (message) => {\n if (message.id) {\n this[kLastEventId] = message.id\n }\n\n const messageEvent = new MessageEvent(\n message.event ? message.event : 'message',\n {\n data: message.data,\n origin: this[kRequest].url,\n lastEventId: this[kLastEventId],\n cancelable: true,\n },\n )\n\n this[kOnAnyMessage]?.(messageEvent)\n this.dispatchEvent(messageEvent)\n },\n retry: (reconnectionTime) => {\n this[kReconnectionTime] = reconnectionTime\n },\n abort: () => {\n throw new Error('Stream abort is not implemented')\n },\n close: () => {\n this.failConnection()\n },\n })\n\n response\n .body!.pipeTo(parsingStream)\n .then(() => {\n this.processResponseEndOfBody(response)\n })\n .catch(() => {\n this.failConnection()\n })\n }\n\n private processResponseEndOfBody(response: Response): void {\n if (!isNetworkError(response)) {\n this.reestablishConnection()\n }\n }\n\n private async reestablishConnection(): Promise<void> {\n queueMicrotask(() => {\n if (this.readyState === this.CLOSED) {\n return\n }\n\n this.readyState = this.CONNECTING\n this.dispatchEvent(new Event('error'))\n })\n\n const signal = this[kAbortController].signal\n\n if (signal.aborted) {\n return\n }\n\n const aborted = new DeferredPromise<void>()\n const onAbort = () => aborted.resolve()\n signal.addEventListener('abort', onAbort, { once: true })\n\n await Promise.race([delay(this[kReconnectionTime]), aborted]).finally(\n () => {\n signal.removeEventListener('abort', onAbort)\n },\n )\n\n if (signal.aborted) {\n return\n }\n\n queueMicrotask(async () => {\n if (this.readyState !== this.CONNECTING) {\n return\n }\n\n if (this[kLastEventId] !== '') {\n this[kRequest].headers.set('last-event-id', this[kLastEventId])\n }\n\n await this.connect()\n })\n }\n\n private failConnection(): void {\n queueMicrotask(() => {\n if (this.readyState !== this.CLOSED) {\n this.readyState = this.CLOSED\n this.dispatchEvent(new Event('error'))\n }\n })\n }\n}\n\n/**\n * Checks if the given `Response` instance is a network error.\n * @see https://fetch.spec.whatwg.org/#concept-network-error\n */\nfunction isNetworkError(response: Response): boolean {\n return (\n response.type === 'error' &&\n response.status === 0 &&\n response.statusText === '' &&\n Array.from(response.headers.entries()).length === 0 &&\n response.body === null\n )\n}\n\nconst enum ControlCharacters {\n NewLine = 10,\n CarriageReturn = 13,\n Space = 32,\n Colon = 58,\n}\n\ninterface EventSourceMessage {\n id?: string\n event?: string\n data?: string\n}\n\nclass EventSourceParsingStream extends WritableStream {\n private decoder: TextDecoder\n\n private buffer?: Uint8Array\n private position: number\n private fieldLength?: number\n private discardTrailingNewline = false\n\n private message: EventSourceMessage = {\n id: undefined,\n event: undefined,\n data: undefined,\n }\n\n constructor(\n private underlyingSink: {\n message: (message: EventSourceMessage) => void\n retry?: (reconnectionTime: number) => void\n abort?: (reason: any) => void\n close?: () => void\n },\n ) {\n super({\n write: (chunk) => {\n this.processResponseBodyChunk(chunk)\n },\n abort: (reason) => {\n this.underlyingSink.abort?.(reason)\n },\n close: () => {\n this.underlyingSink.close?.()\n },\n })\n\n this.decoder = new TextDecoder()\n this.position = 0\n }\n\n private resetMessage(): void {\n this.message = {\n id: undefined,\n event: undefined,\n data: undefined,\n }\n }\n\n private processResponseBodyChunk(chunk: Uint8Array): void {\n if (this.buffer == null) {\n this.buffer = chunk\n this.position = 0\n this.fieldLength = -1\n } else {\n const nextBuffer = new Uint8Array(this.buffer.length + chunk.length)\n nextBuffer.set(this.buffer)\n nextBuffer.set(chunk, this.buffer.length)\n this.buffer = nextBuffer\n }\n\n const bufferLength = this.buffer.length\n let lineStart = 0\n\n while (this.position < bufferLength) {\n if (this.discardTrailingNewline) {\n if (this.buffer[this.position] === ControlCharacters.NewLine) {\n lineStart = ++this.position\n }\n\n this.discardTrailingNewline = false\n }\n\n let lineEnd = -1\n\n for (; this.position < bufferLength && lineEnd === -1; ++this.position) {\n switch (this.buffer[this.position]) {\n case ControlCharacters.Colon: {\n if (this.fieldLength === -1) {\n this.fieldLength = this.position - lineStart\n }\n break\n }\n\n case ControlCharacters.CarriageReturn: {\n this.discardTrailingNewline = true\n break\n }\n\n case ControlCharacters.NewLine: {\n lineEnd = this.position\n break\n }\n }\n }\n\n if (lineEnd === -1) {\n break\n }\n\n this.processLine(\n this.buffer.subarray(lineStart, lineEnd),\n this.fieldLength!,\n )\n\n lineStart = this.position\n this.fieldLength = -1\n }\n\n if (lineStart === bufferLength) {\n this.buffer = undefined\n } else if (lineStart !== 0) {\n this.buffer = this.buffer.subarray(lineStart)\n this.position -= lineStart\n }\n }\n\n private processLine(line: Uint8Array, fieldLength: number): void {\n // New line indicates the end of the message. Dispatch it.\n if (line.length === 0) {\n // Prevent dispatching the message if the data is an empty string.\n // That is a no-op per spec.\n if (this.message.data === undefined) {\n this.message.event = undefined\n return\n }\n\n this.underlyingSink.message(this.message)\n this.resetMessage()\n return\n }\n\n // Otherwise, keep accumulating message fields until the new line.\n if (fieldLength > 0) {\n const field = this.decoder.decode(line.subarray(0, fieldLength))\n const valueOffset =\n fieldLength +\n (line[fieldLength + 1] === ControlCharacters.Space ? 2 : 1)\n const value = this.decoder.decode(line.subarray(valueOffset))\n\n switch (field) {\n case 'data': {\n this.message.data = this.message.data\n ? this.message.data + '\\n' + value\n : value\n break\n }\n\n case 'event': {\n this.message.event = value\n break\n }\n\n case 'id': {\n this.message.id = value\n break\n }\n\n case 'retry': {\n /**\n * Apply the retry immediately. Don't buffer onto the current message.\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation\n */\n if (/^\\d+$/.test(value)) {\n this.underlyingSink.retry?.(parseInt(value, 10))\n }\n break\n }\n }\n }\n }\n}\n\ninterface EventStreamMessage {\n id?: string\n event: string\n data?: unknown\n frames: Array<string>\n}\n\ninterface EventStream<EventMap extends EventMapConstraint> {\n client: ServerSentEventClient<EventMap>\n server: ServerSentEventServer\n response: Response\n}\n\n/**\n * Create an event stream out of the given Fetch API `Request`.\n * Returns the following properties:\n * - `client`, to operate on the intercepted request;\n * - `server`, to establish and manage the actual server connection;\n * - `response`, a `Response` to use as the mock response's body.\n *\n * @example\n * http.post('/resource', ({ request }) => {\n * const { client, server, response } = createEventStream(request)\n * client.send({ data: 'hello world' })\n * return response\n * })\n */\nfunction createEventStream<EventMap extends EventMapConstraint>(\n request: Request,\n): EventStream<EventMap> {\n invariant(\n !request.signal.aborted,\n 'Failed to call \"createEventStream\" on the \"%s %s\" request: request aborted',\n request.method,\n request.url,\n )\n\n const { readable, writable } = new TransformStream()\n\n const client = new ServerSentEventClient<EventMap>(writable)\n const server = new ServerSentEventServer({\n request,\n client,\n })\n\n const response = new Response(readable, SSE_RESPONSE_INIT)\n\n request.signal.addEventListener(\n 'abort',\n () => {\n client.close()\n },\n { once: true },\n )\n\n return {\n client,\n server,\n response,\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAA0B;AAC1B,8BAAgC;AAChC,kCAAwB;AAExB,yBAIO;AAGP,mBAAsB;AACtB,0BAA6B;AAC7B,sBAAyB;AACzB,mCAAuB;AACvB,yBAA4B;AAoDrB,MAAM,MAAqC,CAAC,MAAM,aAAa;AACpE,SAAO,IAAI,uBAAuB,MAAM,QAAQ;AAClD;AAEA,MAAM,oBAAkC;AAAA,EACtC,SAAS;AAAA,IACP,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,YAAY;AAAA,EACd;AACF;AAEA,MAAM,+BAEI,+BAAY;AAAA,EACpB;AAAA,EAEA,YAAY,MAAY,UAAkD;AACxE;AAAA,MACE,OAAO,gBAAgB;AAAA,MACvB;AAAA,MACA;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,OAAO,SAAS;AACjC,YAAM,EAAE,QAAQ,QAAQ,SAAS,IAAI;AAAA,QACnC,KAAK;AAAA,MACP;AAEA,aAAO,cAAc,IAAI,KAAK;AAE9B,YAAM,SAAS;AAAA,QACb,GAAG;AAAA,QACH;AAAA,QACA;AAAA,MACF,CAAC;AAED,aAAO;AAAA,IACT,CAAC;AAED,SAAK,WAAW,IAAI,oCAAuC;AAAA,EAC7D;AAAA,EAEA,MAAM,UAAU,MAIb;AACD,QAAI,KAAK,QAAQ,QAAQ,IAAI,QAAQ,MAAM,qBAAqB;AAC9D,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,MAAM,MAAM,UAAU,IAAI;AAE1C,QAAI,WAAW,CAAC,KAAK,mBAAmB,OAAO;AAM7C,YAAM,MAAM,IAAI;AAAA,QACd,SAAS,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,QAKd,UAAU,IAAI,SAAS,eAAe,iBAAiB;AAAA,MACzD,CAAC;AAED,WAAK,oBAAoB,KAAK,SAAS,KAAK,QAAQ;AAAA,IACtD;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,IAAI,OAAgE;AAKxE;AAAA,EACF;AAAA,EAEA,oBACE,SACA,SACM;AACN,UAAM,gBAAY,gCAAY,QAAQ,GAAG;AAGzC,YAAQ,GAAG,WAAW,CAAC,YAAY;AACjC,cAAQ;AAAA,QACN,yBAAS;AAAA,UACP,OAAG,kCAAa,CAAC,sBAAiB,QAAQ,KAAK;AAAA,QACjD;AAAA,QACA;AAAA,QACA,SAAS,oCAAO,MAAM;AAAA,QACtB;AAAA,MACF;AACA,cAAQ,IAAI,QAAQ,MAAM;AAC1B,cAAQ,SAAS;AAAA,IACnB,CAAC;AAED,YAAQ,GAAG,SAAS,MAAM;AACxB,cAAQ;AAAA,QACN,yBAAS,cAAc,OAAG,kCAAa,CAAC,wBAA0B;AAAA,QAClE;AAAA,QACA,UAAU,oCAAO,MAAM;AAAA,QACvB;AAAA,MACF;AACA,cAAQ,IAAI,YAAY,IAAI;AAC5B,cAAQ,SAAS;AAAA,IACnB,CAAC;AAED,YAAQ,GAAG,SAAS,MAAM;AACxB,cAAQ;AAAA,QACN,yBAAS,cAAc,OAAG,kCAAa,CAAC,0BAAqB;AAAA,QAC7D;AAAA,QACA,UAAU,oCAAO,MAAM;AAAA,QACvB;AAAA,MACF;AACA,cAAQ,IAAI,YAAY,IAAI;AAC5B,cAAQ,SAAS;AAAA,IACnB,CAAC;AAAA,EAEH;AACF;AA8BA,MAAM,iBAAiB,OAAO,IAAI,gBAAgB;AAElD,MAAM,sBAEJ;AAAA,EACA,CAAS,cAAc;AAAA,EAEvB;AAAA,EACA;AAAA,EAEA,YAAY,UAA0B;AACpC,SAAK,WAAW,IAAI,YAAY;AAChC,SAAK,UAAU,SAAS,UAAU;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKO,KAAK,SAAiD;AAC3D,QAAI,WAAW,WAAW,QAAQ,SAAS,MAAM;AAC/C,WAAK,WAAW,QAAQ,KAAK;AAC7B;AAAA,IACF;AAEA,SAAK,aAAa;AAAA,MAChB,IAAI,QAAQ;AAAA,MACZ,OAAO,QAAQ;AAAA,MACf,MACE,OAAO,QAAQ,SAAS,WACpB,KAAK,UAAU,QAAQ,IAAI,IAC3B,QAAQ;AAAA,IAChB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,cAAc,OAAc;AACjC,QAAI,iBAAiB,cAAc;AAKjC,WAAK,aAAa;AAAA,QAChB,IAAI,MAAM,eAAe;AAAA,QACzB,OAAO,MAAM,SAAS,YAAY,SAAY,MAAM;AAAA,QACpD,MAAM,MAAM;AAAA,MACd,CAAC;AACD;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,SAAS;AAC1B,WAAK,MAAM;AACX;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,SAAS;AAC1B,WAAK,MAAM;AACX;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,QAAc;AACnB,SAAK,QAAQ,MAAM,EAAE,MAAM,CAAC,UAAU;AACpC,cAAQ,MAAM,KAAK;AACnB,+BAAS;AAAA,QACP;AAAA,MACF;AAAA,IACF,CAAC;AACD,SAAK,cAAc,GAAG,KAAK,OAAO;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKO,QAAc;AACnB,SAAK,QAAQ,MAAM,EAAE,MAAM,CAAC,UAAU;AACpC,cAAQ,MAAM,KAAK;AACnB,+BAAS;AAAA,QACP;AAAA,MACF;AAAA,IACF,CAAC;AACD,SAAK,cAAc,GAAG,KAAK,OAAO;AAAA,EACpC;AAAA,EAEA,WAAW,OAAqB;AAC9B,SAAK,QACF,MAAM,KAAK,SAAS,OAAO,SAAS,KAAK;AAAA;AAAA,CAAM,CAAC,EAChD,MAAM,CAAC,UAAU;AAChB,cAAQ,MAAM,KAAK;AACnB,+BAAS;AAAA,QACP;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACL;AAAA,EAEA,aAAa,SAIJ;AACP,UAAM,SAAwB,CAAC;AAE/B,QAAI,QAAQ,IAAI;AACd,aAAO,KAAK,MAAM,QAAQ,EAAE,EAAE;AAAA,IAChC;AAEA,QAAI,QAAQ,OAAO;AACjB,aAAO,KAAK,SAAS,QAAQ,MAAM,SAAS,CAAC,EAAE;AAAA,IACjD;AAEA,QAAI,QAAQ,QAAQ,MAAM;AAMxB,iBAAW,QAAQ,QAAQ,KAAK,SAAS,EAAE,MAAM,YAAY,GAAG;AAC9D,eAAO,KAAK,QAAQ,IAAI,EAAE;AAAA,MAC5B;AAAA,IACF;AAEA,WAAO,KAAK,IAAI,EAAE;AAElB,SAAK,QACF,MAAM,KAAK,SAAS,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,EAC7C,MAAM,CAAC,UAAU;AAChB,cAAQ,MAAM,KAAK;AACnB,+BAAS;AAAA,QACP;AAAA,MACF;AAAA,IACF,CAAC;AAEH,SAAK,cAAc,GAAG,KAAK,WAAW;AAAA,MACpC,IAAI,QAAQ;AAAA,MACZ,OAAO,QAAQ,OAAO,SAAS,KAAK;AAAA,MACpC,MAAM,QAAQ;AAAA,MACd;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,MAAM,sBAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,EAEA,YAAY,MAAgE;AAC1E,SAAK,WAAW,KAAK;AACrB,SAAK,UAAU,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,UAAuB;AAC5B,UAAM,SAAS,IAAI,sBAAsB,KAAK,SAAS,KAAK;AAAA,MAC1D,iBAAiB,KAAK,SAAS,gBAAgB;AAAA,MAC/C,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,QAKP,QAAQ;AAAA,MACV;AAAA,MACA,QAAQ,KAAK,SAAS;AAAA,IACxB,CAAC;AAED,WAAO,aAAa,IAAI,CAAC,UAAU;AACjC,aAAO,iBAAiB,OAAO;AAAA,QAC7B,QAAQ;AAAA,UACN,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,cAAc;AAAA,QAChB;AAAA,MACF,CAAC;AAID,qBAAe,MAAM;AACnB,YAAI,CAAC,MAAM,kBAAkB;AAC3B,eAAK,QAAQ,cAAc,KAAK;AAAA,QAClC;AAAA,MACF,CAAC;AAAA,IACH;AAGA,WAAO,iBAAiB,SAAS,CAAC,UAAU;AAC1C,aAAO,iBAAiB,OAAO;AAAA,QAC7B,QAAQ;AAAA,UACN,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,cAAc;AAAA,QAChB;AAAA,MACF,CAAC;AAED,qBAAe,MAAM;AAEnB,YAAI,CAAC,MAAM,kBAAkB;AAC3B,eAAK,QAAQ,cAAc,KAAK;AAAA,QAClC;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,WAAO;AAAA,EACT;AACF;AAYA,MAAM,WAAW,OAAO,UAAU;AAClC,MAAM,oBAAoB,OAAO,mBAAmB;AACpD,MAAM,eAAe,OAAO,cAAc;AAC1C,MAAM,mBAAmB,OAAO,kBAAkB;AAClD,MAAM,UAAU,OAAO,SAAS;AAChC,MAAM,aAAa,OAAO,YAAY;AACtC,MAAM,gBAAgB,OAAO,eAAe;AAC5C,MAAM,WAAW,OAAO,UAAU;AAElC,MAAM,8BAA8B,YAAmC;AAAA,EACrE,OAAgB,aAAa;AAAA,EAC7B,OAAgB,OAAO;AAAA,EACvB,OAAgB,SAAS;AAAA,EAET,aAAa,sBAAsB;AAAA,EACnC,OAAO,sBAAsB;AAAA,EAC7B,SAAS,sBAAsB;AAAA,EAExC;AAAA,EACA;AAAA,EACA;AAAA,EAEP,CAAS,QAAQ;AAAA,EACjB,CAAS,iBAAiB;AAAA,EAC1B,CAAS,YAAY;AAAA,EACrB,CAAS,gBAAgB;AAAA,EACzB,CAAS,OAAO,IAAgC;AAAA,EAChD,CAAS,UAAU,IAAuC;AAAA,EAC1D,CAAS,aAAa,IAAuC;AAAA,EAC7D,CAAS,QAAQ,IAAgC;AAAA,EAEjD,YAAY,KAAmB,MAAkC;AAC/D,UAAM;AAEN,SAAK,MAAM,IAAI,IAAI,GAAG,EAAE;AACxB,SAAK,kBAAkB,MAAM,mBAAmB;AAEhD,SAAK,aAAa,KAAK;AAGvB,UAAM,UAAU,IAAI,QAAQ,MAAM,WAAW,CAAC,CAAC;AAC/C,YAAQ,OAAO,UAAU,mBAAmB;AAE5C,SAAK,gBAAgB,IAAI,IAAI,gBAAgB;AAC7C,SAAK,iBAAiB,IAAI;AAC1B,SAAK,YAAY,IAAI;AACrB,SAAK,QAAQ,IAAI,IAAI,QAAQ,KAAK,KAAK;AAAA,MACrC,QAAQ;AAAA,MACR;AAAA,MACA,aAAa,KAAK,kBAAkB,YAAY;AAAA,MAChD,QAAQ,KAAK,gBAAgB,EAAE;AAAA,IACjC,CAAC;AAED,QAAI,MAAM,QAAQ;AAChB,UAAI,KAAK,OAAO,SAAS;AACvB,aAAK,MAAM;AACX;AAAA,MACF;AAEA,WAAK,OAAO,iBAAiB,SAAS,MAAM,KAAK,MAAM,GAAG;AAAA,QACxD,MAAM;AAAA,QACN,QAAQ,KAAK,gBAAgB,EAAE;AAAA,MACjC,CAAC;AAAA,IACH;AAEA,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,IAAI,SAAqC;AACvC,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,IAAI,OAAO,SAA8B;AACvC,QAAI,KAAK,OAAO,GAAG;AACjB,WAAK,oBAAoB,QAAQ,KAAK,OAAO,CAAC;AAAA,IAChD;AACA,SAAK,OAAO,IAAI,QAAQ,KAAK,IAAI;AACjC,SAAK,iBAAiB,QAAQ,KAAK,OAAO,CAAC;AAAA,EAC7C;AAAA,EAEA,IAAI,YAA+C;AACjD,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EACA,IAAI,UAAU,SAAqC;AACjD,QAAI,KAAK,UAAU,GAAG;AACpB,WAAK,oBAAoB,WAAW,EAAE,aAAa,KAAK,UAAU,EAAE,CAAC;AAAA,IACvE;AACA,SAAK,UAAU,IAAI,QAAQ,KAAK,IAAI;AACpC,SAAK,iBAAiB,WAAW,EAAE,aAAa,KAAK,UAAU,EAAE,CAAC;AAAA,EACpE;AAAA,EAEA,IAAI,UAAsC;AACxC,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EACA,IAAI,QAAQ,SAA8B;AACxC,QAAI,KAAK,QAAQ,GAAG;AAClB,WAAK,oBAAoB,SAAS,EAAE,aAAa,KAAK,QAAQ,EAAE,CAAC;AAAA,IACnE;AACA,SAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI;AAClC,SAAK,iBAAiB,SAAS,EAAE,aAAa,KAAK,QAAQ,EAAE,CAAC;AAAA,EAChE;AAAA,EAkBO,iBACL,MACA,UACA,SACM;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAkBO,oBACL,MACA,UACA,SACM;AACN,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEO,cAAc,OAAuB;AAC1C,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC;AAAA,EAEO,QAAc;AACnB,SAAK,gBAAgB,EAAE,MAAM;AAC7B,SAAK,aAAa,KAAK;AAAA,EACzB;AAAA,EAEA,MAAc,UAAU;AACtB,UAAM,MAAM,KAAK,QAAQ,CAAC,EACvB,KAAK,CAAC,aAAa;AAClB,WAAK,gBAAgB,QAAQ;AAAA,IAC/B,CAAC,EACA,MAAM,MAAM;AAGX,WAAK,eAAe;AAAA,IACtB,CAAC;AAAA,EACL;AAAA,EAEQ,gBAAgB,UAA0B;AAChD,QAAI,CAAC,SAAS,MAAM;AAClB,WAAK,eAAe;AACpB;AAAA,IACF;AAEA,QAAI,eAAe,QAAQ,GAAG;AAC5B,WAAK,sBAAsB;AAC3B;AAAA,IACF;AAEA,QACE,SAAS,WAAW,OACpB,SAAS,QAAQ,IAAI,cAAc,MAAM,qBACzC;AACA,WAAK,eAAe;AACpB;AAAA,IACF;AAEA,SAAK,mBAAmB;AACxB,SAAK,sBAAsB,QAAQ;AAAA,EACrC;AAAA,EAEQ,qBAA2B;AACjC,mBAAe,MAAM;AACnB,UAAI,KAAK,eAAe,KAAK,QAAQ;AACnC,aAAK,aAAa,KAAK;AACvB,aAAK,cAAc,IAAI,MAAM,MAAM,CAAC;AAAA,MACtC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,sBAAsB,UAA0B;AACtD,UAAM,gBAAgB,IAAI,yBAAyB;AAAA,MACjD,SAAS,CAAC,YAAY;AACpB,YAAI,QAAQ,IAAI;AACd,eAAK,YAAY,IAAI,QAAQ;AAAA,QAC/B;AAEA,cAAM,eAAe,IAAI;AAAA,UACvB,QAAQ,QAAQ,QAAQ,QAAQ;AAAA,UAChC;AAAA,YACE,MAAM,QAAQ;AAAA,YACd,QAAQ,KAAK,QAAQ,EAAE;AAAA,YACvB,aAAa,KAAK,YAAY;AAAA,YAC9B,YAAY;AAAA,UACd;AAAA,QACF;AAEA,aAAK,aAAa,IAAI,YAAY;AAClC,aAAK,cAAc,YAAY;AAAA,MACjC;AAAA,MACA,OAAO,CAAC,qBAAqB;AAC3B,aAAK,iBAAiB,IAAI;AAAA,MAC5B;AAAA,MACA,OAAO,MAAM;AACX,cAAM,IAAI,MAAM,iCAAiC;AAAA,MACnD;AAAA,MACA,OAAO,MAAM;AACX,aAAK,eAAe;AAAA,MACtB;AAAA,IACF,CAAC;AAED,aACG,KAAM,OAAO,aAAa,EAC1B,KAAK,MAAM;AACV,WAAK,yBAAyB,QAAQ;AAAA,IACxC,CAAC,EACA,MAAM,MAAM;AACX,WAAK,eAAe;AAAA,IACtB,CAAC;AAAA,EACL;AAAA,EAEQ,yBAAyB,UAA0B;AACzD,QAAI,CAAC,eAAe,QAAQ,GAAG;AAC7B,WAAK,sBAAsB;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAc,wBAAuC;AACnD,mBAAe,MAAM;AACnB,UAAI,KAAK,eAAe,KAAK,QAAQ;AACnC;AAAA,MACF;AAEA,WAAK,aAAa,KAAK;AACvB,WAAK,cAAc,IAAI,MAAM,OAAO,CAAC;AAAA,IACvC,CAAC;AAED,UAAM,SAAS,KAAK,gBAAgB,EAAE;AAEtC,QAAI,OAAO,SAAS;AAClB;AAAA,IACF;AAEA,UAAM,UAAU,IAAI,wCAAsB;AAC1C,UAAM,UAAU,MAAM,QAAQ,QAAQ;AACtC,WAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAExD,UAAM,QAAQ,KAAK,KAAC,oBAAM,KAAK,iBAAiB,CAAC,GAAG,OAAO,CAAC,EAAE;AAAA,MAC5D,MAAM;AACJ,eAAO,oBAAoB,SAAS,OAAO;AAAA,MAC7C;AAAA,IACF;AAEA,QAAI,OAAO,SAAS;AAClB;AAAA,IACF;AAEA,mBAAe,YAAY;AACzB,UAAI,KAAK,eAAe,KAAK,YAAY;AACvC;AAAA,MACF;AAEA,UAAI,KAAK,YAAY,MAAM,IAAI;AAC7B,aAAK,QAAQ,EAAE,QAAQ,IAAI,iBAAiB,KAAK,YAAY,CAAC;AAAA,MAChE;AAEA,YAAM,KAAK,QAAQ;AAAA,IACrB,CAAC;AAAA,EACH;AAAA,EAEQ,iBAAuB;AAC7B,mBAAe,MAAM;AACnB,UAAI,KAAK,eAAe,KAAK,QAAQ;AACnC,aAAK,aAAa,KAAK;AACvB,aAAK,cAAc,IAAI,MAAM,OAAO,CAAC;AAAA,MACvC;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAMA,SAAS,eAAe,UAA6B;AACnD,SACE,SAAS,SAAS,WAClB,SAAS,WAAW,KACpB,SAAS,eAAe,MACxB,MAAM,KAAK,SAAS,QAAQ,QAAQ,CAAC,EAAE,WAAW,KAClD,SAAS,SAAS;AAEtB;AAEA,IAAW,oBAAX,kBAAWA,uBAAX;AACE,EAAAA,sCAAA,aAAU,MAAV;AACA,EAAAA,sCAAA,oBAAiB,MAAjB;AACA,EAAAA,sCAAA,WAAQ,MAAR;AACA,EAAAA,sCAAA,WAAQ,MAAR;AAJS,SAAAA;AAAA,GAAA;AAaX,MAAM,iCAAiC,eAAe;AAAA,EAcpD,YACU,gBAMR;AACA,UAAM;AAAA,MACJ,OAAO,CAAC,UAAU;AAChB,aAAK,yBAAyB,KAAK;AAAA,MACrC;AAAA,MACA,OAAO,CAAC,WAAW;AACjB,aAAK,eAAe,QAAQ,MAAM;AAAA,MACpC;AAAA,MACA,OAAO,MAAM;AACX,aAAK,eAAe,QAAQ;AAAA,MAC9B;AAAA,IACF,CAAC;AAjBO;AAmBR,SAAK,UAAU,IAAI,YAAY;AAC/B,SAAK,WAAW;AAAA,EAClB;AAAA,EAnCQ;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAyB;AAAA,EAEzB,UAA8B;AAAA,IACpC,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EA0BQ,eAAqB;AAC3B,SAAK,UAAU;AAAA,MACb,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEQ,yBAAyB,OAAyB;AACxD,QAAI,KAAK,UAAU,MAAM;AACvB,WAAK,SAAS;AACd,WAAK,WAAW;AAChB,WAAK,cAAc;AAAA,IACrB,OAAO;AACL,YAAM,aAAa,IAAI,WAAW,KAAK,OAAO,SAAS,MAAM,MAAM;AACnE,iBAAW,IAAI,KAAK,MAAM;AAC1B,iBAAW,IAAI,OAAO,KAAK,OAAO,MAAM;AACxC,WAAK,SAAS;AAAA,IAChB;AAEA,UAAM,eAAe,KAAK,OAAO;AACjC,QAAI,YAAY;AAEhB,WAAO,KAAK,WAAW,cAAc;AACnC,UAAI,KAAK,wBAAwB;AAC/B,YAAI,KAAK,OAAO,KAAK,QAAQ,MAAM,kBAA2B;AAC5D,sBAAY,EAAE,KAAK;AAAA,QACrB;AAEA,aAAK,yBAAyB;AAAA,MAChC;AAEA,UAAI,UAAU;AAEd,aAAO,KAAK,WAAW,gBAAgB,YAAY,IAAI,EAAE,KAAK,UAAU;AACtE,gBAAQ,KAAK,OAAO,KAAK,QAAQ,GAAG;AAAA,UAClC,KAAK,gBAAyB;AAC5B,gBAAI,KAAK,gBAAgB,IAAI;AAC3B,mBAAK,cAAc,KAAK,WAAW;AAAA,YACrC;AACA;AAAA,UACF;AAAA,UAEA,KAAK,yBAAkC;AACrC,iBAAK,yBAAyB;AAC9B;AAAA,UACF;AAAA,UAEA,KAAK,kBAA2B;AAC9B,sBAAU,KAAK;AACf;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI,YAAY,IAAI;AAClB;AAAA,MACF;AAEA,WAAK;AAAA,QACH,KAAK,OAAO,SAAS,WAAW,OAAO;AAAA,QACvC,KAAK;AAAA,MACP;AAEA,kBAAY,KAAK;AACjB,WAAK,cAAc;AAAA,IACrB;AAEA,QAAI,cAAc,cAAc;AAC9B,WAAK,SAAS;AAAA,IAChB,WAAW,cAAc,GAAG;AAC1B,WAAK,SAAS,KAAK,OAAO,SAAS,SAAS;AAC5C,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA,EAEQ,YAAY,MAAkB,aAA2B;AAE/D,QAAI,KAAK,WAAW,GAAG;AAGrB,UAAI,KAAK,QAAQ,SAAS,QAAW;AACnC,aAAK,QAAQ,QAAQ;AACrB;AAAA,MACF;AAEA,WAAK,eAAe,QAAQ,KAAK,OAAO;AACxC,WAAK,aAAa;AAClB;AAAA,IACF;AAGA,QAAI,cAAc,GAAG;AACnB,YAAM,QAAQ,KAAK,QAAQ,OAAO,KAAK,SAAS,GAAG,WAAW,CAAC;AAC/D,YAAM,cACJ,eACC,KAAK,cAAc,CAAC,MAAM,iBAA0B,IAAI;AAC3D,YAAM,QAAQ,KAAK,QAAQ,OAAO,KAAK,SAAS,WAAW,CAAC;AAE5D,cAAQ,OAAO;AAAA,QACb,KAAK,QAAQ;AACX,eAAK,QAAQ,OAAO,KAAK,QAAQ,OAC7B,KAAK,QAAQ,OAAO,OAAO,QAC3B;AACJ;AAAA,QACF;AAAA,QAEA,KAAK,SAAS;AACZ,eAAK,QAAQ,QAAQ;AACrB;AAAA,QACF;AAAA,QAEA,KAAK,MAAM;AACT,eAAK,QAAQ,KAAK;AAClB;AAAA,QACF;AAAA,QAEA,KAAK,SAAS;AAKZ,cAAI,QAAQ,KAAK,KAAK,GAAG;AACvB,iBAAK,eAAe,QAAQ,SAAS,OAAO,EAAE,CAAC;AAAA,UACjD;AACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AA6BA,SAAS,kBACP,SACuB;AACvB;AAAA,IACE,CAAC,QAAQ,OAAO;AAAA,IAChB;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AAEA,QAAM,EAAE,UAAU,SAAS,IAAI,IAAI,gBAAgB;AAEnD,QAAM,SAAS,IAAI,sBAAgC,QAAQ;AAC3D,QAAM,SAAS,IAAI,sBAAsB;AAAA,IACvC;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,WAAW,IAAI,SAAS,UAAU,iBAAiB;AAEzD,UAAQ,OAAO;AAAA,IACb;AAAA,IACA,MAAM;AACJ,aAAO,MAAM;AAAA,IACf;AAAA,IACA,EAAE,MAAM,KAAK;AAAA,EACf;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":["ControlCharacters"]}
package/lib/core/sse.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { invariant } from "outvariant";
2
+ import { DeferredPromise } from "@open-draft/deferred-promise";
2
3
  import { Emitter } from "strict-event-emitter";
3
4
  import {
4
5
  HttpHandler
@@ -27,24 +28,16 @@ class ServerSentEventHandler extends HttpHandler {
27
28
  path
28
29
  );
29
30
  super("GET", path, async (info) => {
30
- const stream = new ReadableStream({
31
- start: async (controller) => {
32
- const client = new ServerSentEventClient({
33
- controller,
34
- emitter: this.#emitter
35
- });
36
- const server = new ServerSentEventServer({
37
- request: info.request,
38
- client
39
- });
40
- await resolver({
41
- ...info,
42
- client,
43
- server
44
- });
45
- }
31
+ const { client, server, response } = createEventStream(
32
+ info.request
33
+ );
34
+ client[kClientEmitter] = this.#emitter;
35
+ await resolver({
36
+ ...info,
37
+ client,
38
+ server
46
39
  });
47
- return new Response(stream, SSE_RESPONSE_INIT);
40
+ return response;
48
41
  });
49
42
  this.#emitter = new Emitter();
50
43
  }
@@ -105,14 +98,14 @@ class ServerSentEventHandler extends HttpHandler {
105
98
  });
106
99
  }
107
100
  }
101
+ const kClientEmitter = Symbol.for("kClientEmitter");
108
102
  class ServerSentEventClient {
103
+ [kClientEmitter];
109
104
  #encoder;
110
- #controller;
111
- #emitter;
112
- constructor(args) {
105
+ #writer;
106
+ constructor(writable) {
113
107
  this.#encoder = new TextEncoder();
114
- this.#controller = args.controller;
115
- this.#emitter = args.emitter;
108
+ this.#writer = writable.getWriter();
116
109
  }
117
110
  /**
118
111
  * Sends the given payload to the intercepted `EventSource`.
@@ -155,22 +148,35 @@ class ServerSentEventClient {
155
148
  * error.
156
149
  */
157
150
  error() {
158
- this.#controller.error();
159
- this.#emitter.emit("error");
151
+ this.#writer.abort().catch((error) => {
152
+ console.error(error);
153
+ devUtils.error(
154
+ "Failed to abort server-side EventSource. Please see the original error above."
155
+ );
156
+ });
157
+ this[kClientEmitter]?.emit("error");
160
158
  }
161
159
  /**
162
160
  * Closes the underlying `EventSource`, closing the connection.
163
161
  */
164
162
  close() {
165
- this.#controller.close();
166
- this.#emitter.emit("close");
163
+ this.#writer.close().catch((error) => {
164
+ console.error(error);
165
+ devUtils.error(
166
+ "Failed to close server-side EventSource. Please see the original error above."
167
+ );
168
+ });
169
+ this[kClientEmitter]?.emit("close");
167
170
  }
168
171
  #sendRetry(retry) {
169
- if (typeof retry === "number") {
170
- this.#controller.enqueue(this.#encoder.encode(`retry:${retry}
172
+ this.#writer.write(this.#encoder.encode(`retry:${retry}
171
173
 
172
- `));
173
- }
174
+ `)).catch((error) => {
175
+ console.error(error);
176
+ devUtils.error(
177
+ "Failed to send a retry packet to server-side EventSource. Please see the original error above."
178
+ );
179
+ });
174
180
  }
175
181
  #sendMessage(message) {
176
182
  const frames = [];
@@ -186,8 +192,13 @@ class ServerSentEventClient {
186
192
  }
187
193
  }
188
194
  frames.push("", "");
189
- this.#controller.enqueue(this.#encoder.encode(frames.join("\n")));
190
- this.#emitter.emit("message", {
195
+ this.#writer.write(this.#encoder.encode(frames.join("\n"))).catch((error) => {
196
+ console.error(error);
197
+ devUtils.error(
198
+ "Failed to send a message to server-side EventSource. Please see the original error above."
199
+ );
200
+ });
201
+ this[kClientEmitter]?.emit("message", {
191
202
  id: message.id,
192
203
  event: message.event?.toString() || "message",
193
204
  data: message.data,
@@ -215,7 +226,8 @@ class ServerSentEventServer {
215
226
  * an infinite loop matching against the existing request handler.
216
227
  */
217
228
  accept: "msw/passthrough"
218
- }
229
+ },
230
+ signal: this.#request.signal
219
231
  });
220
232
  source[kOnAnyMessage] = (event) => {
221
233
  Object.defineProperties(event, {
@@ -292,6 +304,16 @@ class ObservableEventSource extends EventTarget {
292
304
  credentials: this.withCredentials ? "include" : "omit",
293
305
  signal: this[kAbortController].signal
294
306
  });
307
+ if (init?.signal) {
308
+ if (init.signal.aborted) {
309
+ this.close();
310
+ return;
311
+ }
312
+ init.signal.addEventListener("abort", () => this.close(), {
313
+ once: true,
314
+ signal: this[kAbortController].signal
315
+ });
316
+ }
295
317
  this.connect();
296
318
  }
297
319
  get onopen() {
@@ -317,7 +339,7 @@ class ObservableEventSource extends EventTarget {
317
339
  get onerror() {
318
340
  return this[kOnError];
319
341
  }
320
- set oneerror(handler) {
342
+ set onerror(handler) {
321
343
  if (this[kOnError]) {
322
344
  this.removeEventListener("error", { handleEvent: this[kOnError] });
323
345
  }
@@ -382,9 +404,6 @@ class ObservableEventSource extends EventTarget {
382
404
  if (message.id) {
383
405
  this[kLastEventId] = message.id;
384
406
  }
385
- if (message.retry) {
386
- this[kReconnectionTime] = message.retry;
387
- }
388
407
  const messageEvent = new MessageEvent(
389
408
  message.event ? message.event : "message",
390
409
  {
@@ -397,6 +416,9 @@ class ObservableEventSource extends EventTarget {
397
416
  this[kOnAnyMessage]?.(messageEvent);
398
417
  this.dispatchEvent(messageEvent);
399
418
  },
419
+ retry: (reconnectionTime) => {
420
+ this[kReconnectionTime] = reconnectionTime;
421
+ },
400
422
  abort: () => {
401
423
  throw new Error("Stream abort is not implemented");
402
424
  },
@@ -423,7 +445,21 @@ class ObservableEventSource extends EventTarget {
423
445
  this.readyState = this.CONNECTING;
424
446
  this.dispatchEvent(new Event("error"));
425
447
  });
426
- await delay(this[kReconnectionTime]);
448
+ const signal = this[kAbortController].signal;
449
+ if (signal.aborted) {
450
+ return;
451
+ }
452
+ const aborted = new DeferredPromise();
453
+ const onAbort = () => aborted.resolve();
454
+ signal.addEventListener("abort", onAbort, { once: true });
455
+ await Promise.race([delay(this[kReconnectionTime]), aborted]).finally(
456
+ () => {
457
+ signal.removeEventListener("abort", onAbort);
458
+ }
459
+ );
460
+ if (signal.aborted) {
461
+ return;
462
+ }
427
463
  queueMicrotask(async () => {
428
464
  if (this.readyState !== this.CONNECTING) {
429
465
  return;
@@ -478,15 +514,13 @@ class EventSourceParsingStream extends WritableStream {
478
514
  message = {
479
515
  id: void 0,
480
516
  event: void 0,
481
- data: void 0,
482
- retry: void 0
517
+ data: void 0
483
518
  };
484
519
  resetMessage() {
485
520
  this.message = {
486
521
  id: void 0,
487
522
  event: void 0,
488
- data: void 0,
489
- retry: void 0
523
+ data: void 0
490
524
  };
491
525
  }
492
526
  processResponseBodyChunk(chunk) {
@@ -573,9 +607,8 @@ class EventSourceParsingStream extends WritableStream {
573
607
  break;
574
608
  }
575
609
  case "retry": {
576
- const retry = parseInt(value, 10);
577
- if (!isNaN(retry)) {
578
- this.message.retry = retry;
610
+ if (/^\d+$/.test(value)) {
611
+ this.underlyingSink.retry?.(parseInt(value, 10));
579
612
  }
580
613
  break;
581
614
  }
@@ -583,6 +616,33 @@ class EventSourceParsingStream extends WritableStream {
583
616
  }
584
617
  }
585
618
  }
619
+ function createEventStream(request) {
620
+ invariant(
621
+ !request.signal.aborted,
622
+ 'Failed to call "createEventStream" on the "%s %s" request: request aborted',
623
+ request.method,
624
+ request.url
625
+ );
626
+ const { readable, writable } = new TransformStream();
627
+ const client = new ServerSentEventClient(writable);
628
+ const server = new ServerSentEventServer({
629
+ request,
630
+ client
631
+ });
632
+ const response = new Response(readable, SSE_RESPONSE_INIT);
633
+ request.signal.addEventListener(
634
+ "abort",
635
+ () => {
636
+ client.close();
637
+ },
638
+ { once: true }
639
+ );
640
+ return {
641
+ client,
642
+ server,
643
+ response
644
+ };
645
+ }
586
646
  export {
587
647
  sse
588
648
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/sse.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { Emitter } from 'strict-event-emitter'\nimport type { ResponseResolver } from './handlers/RequestHandler'\nimport {\n HttpHandler,\n type HttpRequestResolverExtras,\n type HttpRequestParsedResult,\n} from './handlers/HttpHandler'\nimport type { ResponseResolutionContext } from '#core/utils/executeHandlers'\nimport type { Path, PathParams } from './utils/matching/matchRequestUrl'\nimport { delay } from './delay'\nimport { getTimestamp } from './utils/logging/getTimestamp'\nimport { devUtils } from './utils/internal/devUtils'\nimport { colors } from './ws/utils/attachWebSocketLogger'\nimport { toPublicUrl } from './utils/request/toPublicUrl'\n\ntype EventMapConstraint = {\n message?: unknown\n [key: string]: unknown\n [key: symbol | number]: never\n}\n\nexport type ServerSentEventResolverExtras<\n EventMap extends EventMapConstraint,\n Params extends PathParams,\n> = HttpRequestResolverExtras<Params> & {\n client: ServerSentEventClient<EventMap>\n server: ServerSentEventServer\n}\n\nexport type ServerSentEventResolver<\n EventMap extends EventMapConstraint,\n Params extends PathParams,\n> = ResponseResolver<ServerSentEventResolverExtras<EventMap, Params>, any, any>\n\nexport type ServerSentEventRequestHandler = <\n EventMap extends EventMapConstraint = { message: unknown },\n Params extends PathParams<keyof Params> = PathParams,\n RequestPath extends Path = Path,\n>(\n path: RequestPath,\n resolver: ServerSentEventResolver<EventMap, Params>,\n) => HttpHandler\n\nexport type ServerSentEventMessage<\n EventMap extends EventMapConstraint = { message: unknown },\n> =\n | ToEventDiscriminatedUnion<EventMap & { message: unknown }>\n | {\n id?: never\n event?: never\n data?: never\n retry: number\n }\n\n/**\n * Intercept Server-Sent Events (SSE).\n *\n * @example\n * sse('http://localhost:4321', ({ client }) => {\n * client.send({ data: 'hello world' })\n * })\n *\n * @see {@link https://mswjs.io/docs/sse/ Mocking Server-Sent Events}\n * @see {@link https://mswjs.io/docs/api/sse `sse()` API reference}\n */\nexport const sse: ServerSentEventRequestHandler = (path, resolver) => {\n return new ServerSentEventHandler(path, resolver)\n}\n\nconst SSE_RESPONSE_INIT: ResponseInit = {\n headers: {\n 'content-type': 'text/event-stream',\n 'cache-control': 'no-cache',\n connection: 'keep-alive',\n },\n}\n\nclass ServerSentEventHandler<\n EventMap extends EventMapConstraint,\n> extends HttpHandler {\n #emitter: Emitter<ServerSentEventClientEventMap>\n\n constructor(path: Path, resolver: ServerSentEventResolver<EventMap, any>) {\n invariant(\n typeof EventSource !== 'undefined',\n 'Failed to construct a Server-Sent Event handler for path \"%s\": the EventSource API is not supported in this environment',\n path,\n )\n\n super('GET', path, async (info) => {\n const stream = new ReadableStream({\n start: async (controller) => {\n const client = new ServerSentEventClient<EventMap>({\n controller,\n emitter: this.#emitter,\n })\n const server = new ServerSentEventServer({\n request: info.request,\n client,\n })\n\n await resolver({\n ...info,\n client,\n server,\n })\n },\n })\n\n return new Response(stream, SSE_RESPONSE_INIT)\n })\n\n this.#emitter = new Emitter<ServerSentEventClientEventMap>()\n }\n\n async predicate(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n resolutionContext?: ResponseResolutionContext\n }) {\n if (args.request.headers.get('accept') !== 'text/event-stream') {\n return false\n }\n\n const matches = await super.predicate(args)\n\n if (matches && !args.resolutionContext?.quiet) {\n /**\n * @note Log the intercepted request early.\n * Normally, the `this.log()` method is called when the handler returns a response.\n * For SSE, call that method earlier so the logs are in correct order.\n */\n await super.log({\n request: args.request,\n /**\n * @note Construct a placeholder response since SSE response\n * is being streamed and cannot be cloned/consumed for logging.\n */\n response: new Response('[streaming]', SSE_RESPONSE_INIT),\n })\n\n this.#attachClientLogger(args.request, this.#emitter)\n }\n\n return matches\n }\n\n async log(_args: { request: Request; response: Response }): Promise<void> {\n /**\n * @note Skip the default `this.log()` logic so that when this handler is logged\n * upon handling the request, nothing is printed (we log SSE requests early).\n */\n return\n }\n\n #attachClientLogger(\n request: Request,\n emitter: Emitter<ServerSentEventClientEventMap>,\n ): void {\n const publicUrl = toPublicUrl(request.url)\n\n /* eslint-disable no-console */\n emitter.on('message', (payload) => {\n console.groupCollapsed(\n devUtils.formatMessage(\n `${getTimestamp()} SSE %s %c⇣%c ${payload.event}`,\n ),\n publicUrl,\n `color:${colors.mocked}`,\n 'color:inherit',\n )\n console.log(payload.frames)\n console.groupEnd()\n })\n\n emitter.on('error', () => {\n console.groupCollapsed(\n devUtils.formatMessage(`${getTimestamp()} SSE %s %c\\u00D7%c error`),\n publicUrl,\n `color: ${colors.system}`,\n 'color:inherit',\n )\n console.log('Handler:', this)\n console.groupEnd()\n })\n\n emitter.on('close', () => {\n console.groupCollapsed(\n devUtils.formatMessage(`${getTimestamp()} SSE %s %c■%c close`),\n publicUrl,\n `colors:${colors.system}`,\n 'color:inherit',\n )\n console.log('Handler:', this)\n console.groupEnd()\n })\n /* eslint-enable no-console */\n }\n}\n\ntype Values<T> = T[keyof T]\ntype Identity<T> = { [K in keyof T]: T[K] } & unknown\ntype ToEventDiscriminatedUnion<T> = Values<{\n [K in keyof T]: Identity<\n (K extends 'message'\n ? {\n id?: string\n event?: K\n data?: T[K]\n retry?: never\n }\n : {\n id?: string\n event: K\n data?: T[K]\n retry?: never\n }) &\n // Make the `data` field conditionally required through an intersection.\n (undefined extends T[K] ? unknown : { data: unknown })\n >\n}>\n\ntype ServerSentEventClientEventMap = {\n message: [\n payload: {\n id?: string\n event: string\n data?: unknown\n frames: Array<string>\n },\n ]\n error: []\n close: []\n}\n\nclass ServerSentEventClient<\n EventMap extends EventMapConstraint = { message: unknown },\n> {\n #encoder: TextEncoder\n #controller: ReadableStreamDefaultController\n #emitter: Emitter<ServerSentEventClientEventMap>\n\n constructor(args: {\n controller: ReadableStreamDefaultController\n emitter: Emitter<ServerSentEventClientEventMap>\n }) {\n this.#encoder = new TextEncoder()\n this.#controller = args.controller\n this.#emitter = args.emitter\n }\n\n /**\n * Sends the given payload to the intercepted `EventSource`.\n */\n public send(payload: ServerSentEventMessage<EventMap>): void {\n if ('retry' in payload && payload.retry != null) {\n this.#sendRetry(payload.retry)\n return\n }\n\n this.#sendMessage({\n id: payload.id,\n event: payload.event,\n data:\n typeof payload.data === 'object'\n ? JSON.stringify(payload.data)\n : payload.data,\n })\n }\n\n /**\n * Dispatches the given event on the intercepted `EventSource`.\n */\n public dispatchEvent(event: Event) {\n if (event instanceof MessageEvent) {\n /**\n * @note Use the internal send mechanism to skip normalization\n * of the message data (already normalized by the server).\n */\n this.#sendMessage({\n id: event.lastEventId || undefined,\n event: event.type === 'message' ? undefined : event.type,\n data: event.data,\n })\n return\n }\n\n if (event.type === 'error') {\n this.error()\n return\n }\n\n if (event.type === 'close') {\n this.close()\n return\n }\n }\n\n /**\n * Errors the underlying `EventSource`, closing the connection with an error.\n * This is equivalent to aborting the connection and will produce a `TypeError: Failed to fetch`\n * error.\n */\n public error(): void {\n this.#controller.error()\n this.#emitter.emit('error')\n }\n\n /**\n * Closes the underlying `EventSource`, closing the connection.\n */\n public close(): void {\n this.#controller.close()\n this.#emitter.emit('close')\n }\n\n #sendRetry(retry: number): void {\n if (typeof retry === 'number') {\n this.#controller.enqueue(this.#encoder.encode(`retry:${retry}\\n\\n`))\n }\n }\n\n #sendMessage(message: {\n id?: string\n event?: unknown\n data: unknown | undefined\n }): void {\n const frames: Array<string> = []\n\n if (message.id) {\n frames.push(`id:${message.id}`)\n }\n\n if (message.event) {\n frames.push(`event:${message.event.toString()}`)\n }\n\n if (message.data != null) {\n /**\n * Split data on line terminators (LF, CR, or CRLF) and translate them to individual frames.\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream\n */\n for (const line of message.data.toString().split(/\\r\\n|\\r|\\n/)) {\n frames.push(`data:${line}`)\n }\n }\n\n frames.push('', '')\n\n this.#controller.enqueue(this.#encoder.encode(frames.join('\\n')))\n\n this.#emitter.emit('message', {\n id: message.id,\n event: message.event?.toString() || 'message',\n data: message.data,\n frames,\n })\n }\n}\n\nclass ServerSentEventServer {\n #request: Request\n #client: ServerSentEventClient<ServerSentEventClientEventMap>\n\n constructor(args: { request: Request; client: ServerSentEventClient<any> }) {\n this.#request = args.request\n this.#client = args.client\n }\n\n /**\n * Establishes the actual connection for this SSE request\n * and returns the `EventSource` instance.\n */\n public connect(): EventSource {\n const source = new ObservableEventSource(this.#request.url, {\n withCredentials: this.#request.credentials === 'include',\n headers: {\n /**\n * @note Mark this request as passthrough so it doesn't trigger\n * an infinite loop matching against the existing request handler.\n */\n accept: 'msw/passthrough',\n },\n })\n\n source[kOnAnyMessage] = (event) => {\n Object.defineProperties(event, {\n target: {\n value: this,\n enumerable: true,\n writable: true,\n configurable: true,\n },\n })\n\n // Schedule the server-to-client forwarding for the next tick\n // so the user can prevent the message event.\n queueMicrotask(() => {\n if (!event.defaultPrevented) {\n this.#client.dispatchEvent(event)\n }\n })\n }\n\n // Forward stream errors from the actual server to the client.\n source.addEventListener('error', (event) => {\n Object.defineProperties(event, {\n target: {\n value: this,\n enumerable: true,\n writable: true,\n configurable: true,\n },\n })\n\n queueMicrotask(() => {\n // Allow the user to opt-out from this forwarding.\n if (!event.defaultPrevented) {\n this.#client.dispatchEvent(event)\n }\n })\n })\n\n return source\n }\n}\n\ninterface ObservableEventSourceInit extends EventSourceInit {\n headers?: HeadersInit\n}\n\ntype EventHandler<EventType extends Event> = (\n this: EventSource,\n event: EventType,\n) => any\n\nconst kRequest = Symbol('kRequest')\nconst kReconnectionTime = Symbol('kReconnectionTime')\nconst kLastEventId = Symbol('kLastEventId')\nconst kAbortController = Symbol('kAbortController')\nconst kOnOpen = Symbol('kOnOpen')\nconst kOnMessage = Symbol('kOnMessage')\nconst kOnAnyMessage = Symbol('kOnAnyMessage')\nconst kOnError = Symbol('kOnError')\n\nclass ObservableEventSource extends EventTarget implements EventSource {\n static readonly CONNECTING = 0\n static readonly OPEN = 1\n static readonly CLOSED = 2\n\n public readonly CONNECTING = ObservableEventSource.CONNECTING\n public readonly OPEN = ObservableEventSource.OPEN\n public readonly CLOSED = ObservableEventSource.CLOSED\n\n public readyState: number\n public url: string\n public withCredentials: boolean\n\n private [kRequest]: Request\n private [kReconnectionTime]: number\n private [kLastEventId]: string\n private [kAbortController]: AbortController\n private [kOnOpen]: EventHandler<Event> | null = null\n private [kOnMessage]: EventHandler<MessageEvent> | null = null\n private [kOnAnyMessage]: EventHandler<MessageEvent> | null = null\n private [kOnError]: EventHandler<Event> | null = null\n\n constructor(url: string | URL, init?: ObservableEventSourceInit) {\n super()\n\n this.url = new URL(url).href\n this.withCredentials = init?.withCredentials ?? false\n\n this.readyState = this.CONNECTING\n\n // Support custom request init.\n const headers = new Headers(init?.headers || {})\n headers.append('accept', 'text/event-stream')\n\n this[kAbortController] = new AbortController()\n this[kReconnectionTime] = 2000\n this[kLastEventId] = ''\n this[kRequest] = new Request(this.url, {\n method: 'GET',\n headers,\n credentials: this.withCredentials ? 'include' : 'omit',\n signal: this[kAbortController].signal,\n })\n\n this.connect()\n }\n\n get onopen(): EventHandler<Event> | null {\n return this[kOnOpen]\n }\n\n set onopen(handler: EventHandler<Event>) {\n if (this[kOnOpen]) {\n this.removeEventListener('open', this[kOnOpen])\n }\n this[kOnOpen] = handler.bind(this)\n this.addEventListener('open', this[kOnOpen])\n }\n\n get onmessage(): EventHandler<MessageEvent> | null {\n return this[kOnMessage]\n }\n set onmessage(handler: EventHandler<MessageEvent>) {\n if (this[kOnMessage]) {\n this.removeEventListener('message', { handleEvent: this[kOnMessage] })\n }\n this[kOnMessage] = handler.bind(this)\n this.addEventListener('message', { handleEvent: this[kOnMessage] })\n }\n\n get onerror(): EventHandler<Event> | null {\n return this[kOnError]\n }\n set oneerror(handler: EventHandler<Event>) {\n if (this[kOnError]) {\n this.removeEventListener('error', { handleEvent: this[kOnError] })\n }\n this[kOnError] = handler.bind(this)\n this.addEventListener('error', { handleEvent: this[kOnError] })\n }\n\n public addEventListener<K extends keyof EventSourceEventMap>(\n type: K,\n listener: EventHandler<EventSourceEventMap[K]>,\n options?: boolean | AddEventListenerOptions,\n ): void\n public addEventListener(\n type: string,\n listener: EventHandler<MessageEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void\n public addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void\n\n public addEventListener(\n type: string,\n listener: EventHandler<MessageEvent> | EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void {\n super.addEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n )\n }\n\n public removeEventListener<K extends keyof EventSourceEventMap>(\n type: K,\n listener: (this: EventSource, ev: EventSourceEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ): void\n public removeEventListener(\n type: string,\n listener: (this: EventSource, event: MessageEvent) => any,\n options?: boolean | EventListenerOptions,\n ): void\n public removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void\n\n public removeEventListener(\n type: string,\n listener: EventHandler<MessageEvent> | EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void {\n super.removeEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n )\n }\n\n public dispatchEvent(event: Event): boolean {\n return super.dispatchEvent(event)\n }\n\n public close(): void {\n this[kAbortController].abort()\n this.readyState = this.CLOSED\n }\n\n private async connect() {\n await fetch(this[kRequest])\n .then((response) => {\n this.processResponse(response)\n })\n .catch(() => {\n // Fail the connection on request errors instead of\n // throwing a generic \"Failed to fetch\" error.\n this.failConnection()\n })\n }\n\n private processResponse(response: Response): void {\n if (!response.body) {\n this.failConnection()\n return\n }\n\n if (isNetworkError(response)) {\n this.reestablishConnection()\n return\n }\n\n if (\n response.status !== 200 ||\n response.headers.get('content-type') !== 'text/event-stream'\n ) {\n this.failConnection()\n return\n }\n\n this.announceConnection()\n this.interpretResponseBody(response)\n }\n\n private announceConnection(): void {\n queueMicrotask(() => {\n if (this.readyState !== this.CLOSED) {\n this.readyState = this.OPEN\n this.dispatchEvent(new Event('open'))\n }\n })\n }\n\n private interpretResponseBody(response: Response): void {\n const parsingStream = new EventSourceParsingStream({\n message: (message) => {\n if (message.id) {\n this[kLastEventId] = message.id\n }\n\n if (message.retry) {\n this[kReconnectionTime] = message.retry\n }\n\n const messageEvent = new MessageEvent(\n message.event ? message.event : 'message',\n {\n data: message.data,\n origin: this[kRequest].url,\n lastEventId: this[kLastEventId],\n cancelable: true,\n },\n )\n\n this[kOnAnyMessage]?.(messageEvent)\n this.dispatchEvent(messageEvent)\n },\n abort: () => {\n throw new Error('Stream abort is not implemented')\n },\n close: () => {\n this.failConnection()\n },\n })\n\n response\n .body!.pipeTo(parsingStream)\n .then(() => {\n this.processResponseEndOfBody(response)\n })\n .catch(() => {\n this.failConnection()\n })\n }\n\n private processResponseEndOfBody(response: Response): void {\n if (!isNetworkError(response)) {\n this.reestablishConnection()\n }\n }\n\n private async reestablishConnection(): Promise<void> {\n queueMicrotask(() => {\n if (this.readyState === this.CLOSED) {\n return\n }\n\n this.readyState = this.CONNECTING\n this.dispatchEvent(new Event('error'))\n })\n\n await delay(this[kReconnectionTime])\n\n queueMicrotask(async () => {\n if (this.readyState !== this.CONNECTING) {\n return\n }\n\n if (this[kLastEventId] !== '') {\n this[kRequest].headers.set('last-event-id', this[kLastEventId])\n }\n\n await this.connect()\n })\n }\n\n private failConnection(): void {\n queueMicrotask(() => {\n if (this.readyState !== this.CLOSED) {\n this.readyState = this.CLOSED\n this.dispatchEvent(new Event('error'))\n }\n })\n }\n}\n\n/**\n * Checks if the given `Response` instance is a network error.\n * @see https://fetch.spec.whatwg.org/#concept-network-error\n */\nfunction isNetworkError(response: Response): boolean {\n return (\n response.type === 'error' &&\n response.status === 0 &&\n response.statusText === '' &&\n Array.from(response.headers.entries()).length === 0 &&\n response.body === null\n )\n}\n\nconst enum ControlCharacters {\n NewLine = 10,\n CarriageReturn = 13,\n Space = 32,\n Colon = 58,\n}\n\ninterface EventSourceMessage {\n id?: string\n event?: string\n data?: string\n retry?: number\n}\n\nclass EventSourceParsingStream extends WritableStream {\n private decoder: TextDecoder\n\n private buffer?: Uint8Array\n private position: number\n private fieldLength?: number\n private discardTrailingNewline = false\n\n private message: EventSourceMessage = {\n id: undefined,\n event: undefined,\n data: undefined,\n retry: undefined,\n }\n\n constructor(\n private underlyingSink: {\n message: (message: EventSourceMessage) => void\n abort?: (reason: any) => void\n close?: () => void\n },\n ) {\n super({\n write: (chunk) => {\n this.processResponseBodyChunk(chunk)\n },\n abort: (reason) => {\n this.underlyingSink.abort?.(reason)\n },\n close: () => {\n this.underlyingSink.close?.()\n },\n })\n\n this.decoder = new TextDecoder()\n this.position = 0\n }\n\n private resetMessage(): void {\n this.message = {\n id: undefined,\n event: undefined,\n data: undefined,\n retry: undefined,\n }\n }\n\n private processResponseBodyChunk(chunk: Uint8Array): void {\n if (this.buffer == null) {\n this.buffer = chunk\n this.position = 0\n this.fieldLength = -1\n } else {\n const nextBuffer = new Uint8Array(this.buffer.length + chunk.length)\n nextBuffer.set(this.buffer)\n nextBuffer.set(chunk, this.buffer.length)\n this.buffer = nextBuffer\n }\n\n const bufferLength = this.buffer.length\n let lineStart = 0\n\n while (this.position < bufferLength) {\n if (this.discardTrailingNewline) {\n if (this.buffer[this.position] === ControlCharacters.NewLine) {\n lineStart = ++this.position\n }\n\n this.discardTrailingNewline = false\n }\n\n let lineEnd = -1\n\n for (; this.position < bufferLength && lineEnd === -1; ++this.position) {\n switch (this.buffer[this.position]) {\n case ControlCharacters.Colon: {\n if (this.fieldLength === -1) {\n this.fieldLength = this.position - lineStart\n }\n break\n }\n\n case ControlCharacters.CarriageReturn: {\n this.discardTrailingNewline = true\n break\n }\n\n case ControlCharacters.NewLine: {\n lineEnd = this.position\n break\n }\n }\n }\n\n if (lineEnd === -1) {\n break\n }\n\n this.processLine(\n this.buffer.subarray(lineStart, lineEnd),\n this.fieldLength!,\n )\n\n lineStart = this.position\n this.fieldLength = -1\n }\n\n if (lineStart === bufferLength) {\n this.buffer = undefined\n } else if (lineStart !== 0) {\n this.buffer = this.buffer.subarray(lineStart)\n this.position -= lineStart\n }\n }\n\n private processLine(line: Uint8Array, fieldLength: number): void {\n // New line indicates the end of the message. Dispatch it.\n if (line.length === 0) {\n // Prevent dispatching the message if the data is an empty string.\n // That is a no-op per spec.\n if (this.message.data === undefined) {\n this.message.event = undefined\n return\n }\n\n this.underlyingSink.message(this.message)\n this.resetMessage()\n return\n }\n\n // Otherwise, keep accumulating message fields until the new line.\n if (fieldLength > 0) {\n const field = this.decoder.decode(line.subarray(0, fieldLength))\n const valueOffset =\n fieldLength +\n (line[fieldLength + 1] === ControlCharacters.Space ? 2 : 1)\n const value = this.decoder.decode(line.subarray(valueOffset))\n\n switch (field) {\n case 'data': {\n this.message.data = this.message.data\n ? this.message.data + '\\n' + value\n : value\n break\n }\n\n case 'event': {\n this.message.event = value\n break\n }\n\n case 'id': {\n this.message.id = value\n break\n }\n\n case 'retry': {\n const retry = parseInt(value, 10)\n\n if (!isNaN(retry)) {\n this.message.retry = retry\n }\n break\n }\n }\n }\n }\n}\n"],"mappings":"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","names":["ControlCharacters"]}
1
+ {"version":3,"sources":["../../src/core/sse.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { Emitter } from 'strict-event-emitter'\nimport type { ResponseResolver } from './handlers/RequestHandler'\nimport {\n HttpHandler,\n type HttpRequestResolverExtras,\n type HttpRequestParsedResult,\n} from './handlers/HttpHandler'\nimport type { ResponseResolutionContext } from '#core/utils/executeHandlers'\nimport type { Path, PathParams } from './utils/matching/matchRequestUrl'\nimport { delay } from './delay'\nimport { getTimestamp } from './utils/logging/getTimestamp'\nimport { devUtils } from './utils/internal/devUtils'\nimport { colors } from './ws/utils/attachWebSocketLogger'\nimport { toPublicUrl } from './utils/request/toPublicUrl'\n\ntype EventMapConstraint = {\n message?: unknown\n [key: string]: unknown\n [key: symbol | number]: never\n}\n\nexport type ServerSentEventResolverExtras<\n EventMap extends EventMapConstraint,\n Params extends PathParams,\n> = HttpRequestResolverExtras<Params> & {\n client: ServerSentEventClient<EventMap>\n server: ServerSentEventServer\n}\n\nexport type ServerSentEventResolver<\n EventMap extends EventMapConstraint,\n Params extends PathParams,\n> = ResponseResolver<ServerSentEventResolverExtras<EventMap, Params>, any, any>\n\nexport type ServerSentEventRequestHandler = <\n EventMap extends EventMapConstraint = { message: unknown },\n Params extends PathParams<keyof Params> = PathParams,\n RequestPath extends Path = Path,\n>(\n path: RequestPath,\n resolver: ServerSentEventResolver<EventMap, Params>,\n) => HttpHandler\n\nexport type ServerSentEventMessage<\n EventMap extends EventMapConstraint = { message: unknown },\n> =\n | ToEventDiscriminatedUnion<EventMap & { message: unknown }>\n | {\n id?: never\n event?: never\n data?: never\n retry: number\n }\n\n/**\n * Intercept Server-Sent Events (SSE).\n *\n * @example\n * sse('http://localhost:4321', ({ client }) => {\n * client.send({ data: 'hello world' })\n * })\n *\n * @see {@link https://mswjs.io/docs/sse/ Mocking Server-Sent Events}\n * @see {@link https://mswjs.io/docs/api/sse `sse()` API reference}\n */\nexport const sse: ServerSentEventRequestHandler = (path, resolver) => {\n return new ServerSentEventHandler(path, resolver)\n}\n\nconst SSE_RESPONSE_INIT: ResponseInit = {\n headers: {\n 'content-type': 'text/event-stream',\n 'cache-control': 'no-cache',\n connection: 'keep-alive',\n },\n}\n\nclass ServerSentEventHandler<\n EventMap extends EventMapConstraint,\n> extends HttpHandler {\n #emitter: Emitter<ServerSentEventClientEventMap>\n\n constructor(path: Path, resolver: ServerSentEventResolver<EventMap, any>) {\n invariant(\n typeof EventSource !== 'undefined',\n 'Failed to construct a Server-Sent Event handler for path \"%s\": the EventSource API is not supported in this environment',\n path,\n )\n\n super('GET', path, async (info) => {\n const { client, server, response } = createEventStream<EventMap>(\n info.request,\n )\n\n client[kClientEmitter] = this.#emitter\n\n await resolver({\n ...info,\n client,\n server,\n })\n\n return response\n })\n\n this.#emitter = new Emitter<ServerSentEventClientEventMap>()\n }\n\n async predicate(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n resolutionContext?: ResponseResolutionContext\n }) {\n if (args.request.headers.get('accept') !== 'text/event-stream') {\n return false\n }\n\n const matches = await super.predicate(args)\n\n if (matches && !args.resolutionContext?.quiet) {\n /**\n * @note Log the intercepted request early.\n * Normally, the `this.log()` method is called when the handler returns a response.\n * For SSE, call that method earlier so the logs are in correct order.\n */\n await super.log({\n request: args.request,\n /**\n * @note Construct a placeholder response since SSE response\n * is being streamed and cannot be cloned/consumed for logging.\n */\n response: new Response('[streaming]', SSE_RESPONSE_INIT),\n })\n\n this.#attachClientLogger(args.request, this.#emitter)\n }\n\n return matches\n }\n\n async log(_args: { request: Request; response: Response }): Promise<void> {\n /**\n * @note Skip the default `this.log()` logic so that when this handler is logged\n * upon handling the request, nothing is printed (we log SSE requests early).\n */\n return\n }\n\n #attachClientLogger(\n request: Request,\n emitter: Emitter<ServerSentEventClientEventMap>,\n ): void {\n const publicUrl = toPublicUrl(request.url)\n\n /* eslint-disable no-console */\n emitter.on('message', (payload) => {\n console.groupCollapsed(\n devUtils.formatMessage(\n `${getTimestamp()} SSE %s %c⇣%c ${payload.event}`,\n ),\n publicUrl,\n `color:${colors.mocked}`,\n 'color:inherit',\n )\n console.log(payload.frames)\n console.groupEnd()\n })\n\n emitter.on('error', () => {\n console.groupCollapsed(\n devUtils.formatMessage(`${getTimestamp()} SSE %s %c\\u00D7%c error`),\n publicUrl,\n `color: ${colors.system}`,\n 'color:inherit',\n )\n console.log('Handler:', this)\n console.groupEnd()\n })\n\n emitter.on('close', () => {\n console.groupCollapsed(\n devUtils.formatMessage(`${getTimestamp()} SSE %s %c■%c close`),\n publicUrl,\n `colors:${colors.system}`,\n 'color:inherit',\n )\n console.log('Handler:', this)\n console.groupEnd()\n })\n /* eslint-enable no-console */\n }\n}\n\ntype Values<T> = T[keyof T]\ntype Identity<T> = { [K in keyof T]: T[K] } & unknown\ntype ToEventDiscriminatedUnion<T> = Values<{\n [K in keyof T]: Identity<\n (K extends 'message'\n ? {\n id?: string\n event?: K\n data?: T[K]\n retry?: never\n }\n : {\n id?: string\n event: K\n data?: T[K]\n retry?: never\n }) &\n // Make the `data` field conditionally required through an intersection.\n (undefined extends T[K] ? unknown : { data: unknown })\n >\n}>\n\ntype ServerSentEventClientEventMap = {\n message: [payload: EventStreamMessage]\n error: []\n close: []\n}\n\nconst kClientEmitter = Symbol.for('kClientEmitter')\n\nclass ServerSentEventClient<\n EventMap extends EventMapConstraint = { message: unknown },\n> {\n private [kClientEmitter]?: Emitter<ServerSentEventClientEventMap>\n\n #encoder: TextEncoder\n #writer: WritableStreamDefaultWriter\n\n constructor(writable: WritableStream) {\n this.#encoder = new TextEncoder()\n this.#writer = writable.getWriter()\n }\n\n /**\n * Sends the given payload to the intercepted `EventSource`.\n */\n public send(payload: ServerSentEventMessage<EventMap>): void {\n if ('retry' in payload && payload.retry != null) {\n this.#sendRetry(payload.retry)\n return\n }\n\n this.#sendMessage({\n id: payload.id,\n event: payload.event,\n data:\n typeof payload.data === 'object'\n ? JSON.stringify(payload.data)\n : payload.data,\n })\n }\n\n /**\n * Dispatches the given event on the intercepted `EventSource`.\n */\n public dispatchEvent(event: Event) {\n if (event instanceof MessageEvent) {\n /**\n * @note Use the internal send mechanism to skip normalization\n * of the message data (already normalized by the server).\n */\n this.#sendMessage({\n id: event.lastEventId || undefined,\n event: event.type === 'message' ? undefined : event.type,\n data: event.data,\n })\n return\n }\n\n if (event.type === 'error') {\n this.error()\n return\n }\n\n if (event.type === 'close') {\n this.close()\n return\n }\n }\n\n /**\n * Errors the underlying `EventSource`, closing the connection with an error.\n * This is equivalent to aborting the connection and will produce a `TypeError: Failed to fetch`\n * error.\n */\n public error(): void {\n this.#writer.abort().catch((error) => {\n console.error(error)\n devUtils.error(\n 'Failed to abort server-side EventSource. Please see the original error above.',\n )\n })\n this[kClientEmitter]?.emit('error')\n }\n\n /**\n * Closes the underlying `EventSource`, closing the connection.\n */\n public close(): void {\n this.#writer.close().catch((error) => {\n console.error(error)\n devUtils.error(\n 'Failed to close server-side EventSource. Please see the original error above.',\n )\n })\n this[kClientEmitter]?.emit('close')\n }\n\n #sendRetry(retry: number): void {\n this.#writer\n .write(this.#encoder.encode(`retry:${retry}\\n\\n`))\n .catch((error) => {\n console.error(error)\n devUtils.error(\n 'Failed to send a retry packet to server-side EventSource. Please see the original error above.',\n )\n })\n }\n\n #sendMessage(message: {\n id?: string\n event?: unknown\n data: unknown | undefined\n }): void {\n const frames: Array<string> = []\n\n if (message.id) {\n frames.push(`id:${message.id}`)\n }\n\n if (message.event) {\n frames.push(`event:${message.event.toString()}`)\n }\n\n if (message.data != null) {\n /**\n * Split data on line terminators (LF, CR, or CRLF) and translate them to individual frames.\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream\n */\n for (const line of message.data.toString().split(/\\r\\n|\\r|\\n/)) {\n frames.push(`data:${line}`)\n }\n }\n\n frames.push('', '')\n\n this.#writer\n .write(this.#encoder.encode(frames.join('\\n')))\n .catch((error) => {\n console.error(error)\n devUtils.error(\n 'Failed to send a message to server-side EventSource. Please see the original error above.',\n )\n })\n\n this[kClientEmitter]?.emit('message', {\n id: message.id,\n event: message.event?.toString() || 'message',\n data: message.data,\n frames,\n })\n }\n}\n\nclass ServerSentEventServer {\n #request: Request\n #client: ServerSentEventClient<ServerSentEventClientEventMap>\n\n constructor(args: { request: Request; client: ServerSentEventClient<any> }) {\n this.#request = args.request\n this.#client = args.client\n }\n\n /**\n * Establishes the actual connection for this SSE request\n * and returns the `EventSource` instance.\n */\n public connect(): EventSource {\n const source = new ObservableEventSource(this.#request.url, {\n withCredentials: this.#request.credentials === 'include',\n headers: {\n /**\n * @note Mark this request as passthrough so it doesn't trigger\n * an infinite loop matching against the existing request handler.\n */\n accept: 'msw/passthrough',\n },\n signal: this.#request.signal,\n })\n\n source[kOnAnyMessage] = (event) => {\n Object.defineProperties(event, {\n target: {\n value: this,\n enumerable: true,\n writable: true,\n configurable: true,\n },\n })\n\n // Schedule the server-to-client forwarding for the next tick\n // so the user can prevent the message event.\n queueMicrotask(() => {\n if (!event.defaultPrevented) {\n this.#client.dispatchEvent(event)\n }\n })\n }\n\n // Forward stream errors from the actual server to the client.\n source.addEventListener('error', (event) => {\n Object.defineProperties(event, {\n target: {\n value: this,\n enumerable: true,\n writable: true,\n configurable: true,\n },\n })\n\n queueMicrotask(() => {\n // Allow the user to opt-out from this forwarding.\n if (!event.defaultPrevented) {\n this.#client.dispatchEvent(event)\n }\n })\n })\n\n return source\n }\n}\n\ninterface ObservableEventSourceInit extends EventSourceInit {\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\ntype EventHandler<EventType extends Event> = (\n this: EventSource,\n event: EventType,\n) => any\n\nconst kRequest = Symbol('kRequest')\nconst kReconnectionTime = Symbol('kReconnectionTime')\nconst kLastEventId = Symbol('kLastEventId')\nconst kAbortController = Symbol('kAbortController')\nconst kOnOpen = Symbol('kOnOpen')\nconst kOnMessage = Symbol('kOnMessage')\nconst kOnAnyMessage = Symbol('kOnAnyMessage')\nconst kOnError = Symbol('kOnError')\n\nclass ObservableEventSource extends EventTarget implements EventSource {\n static readonly CONNECTING = 0\n static readonly OPEN = 1\n static readonly CLOSED = 2\n\n public readonly CONNECTING = ObservableEventSource.CONNECTING\n public readonly OPEN = ObservableEventSource.OPEN\n public readonly CLOSED = ObservableEventSource.CLOSED\n\n public readyState: number\n public url: string\n public withCredentials: boolean\n\n private [kRequest]: Request\n private [kReconnectionTime]: number\n private [kLastEventId]: string\n private [kAbortController]: AbortController\n private [kOnOpen]: EventHandler<Event> | null = null\n private [kOnMessage]: EventHandler<MessageEvent> | null = null\n private [kOnAnyMessage]: EventHandler<MessageEvent> | null = null\n private [kOnError]: EventHandler<Event> | null = null\n\n constructor(url: string | URL, init?: ObservableEventSourceInit) {\n super()\n\n this.url = new URL(url).href\n this.withCredentials = init?.withCredentials ?? false\n\n this.readyState = this.CONNECTING\n\n // Support custom request init.\n const headers = new Headers(init?.headers || {})\n headers.append('accept', 'text/event-stream')\n\n this[kAbortController] = new AbortController()\n this[kReconnectionTime] = 2000\n this[kLastEventId] = ''\n this[kRequest] = new Request(this.url, {\n method: 'GET',\n headers,\n credentials: this.withCredentials ? 'include' : 'omit',\n signal: this[kAbortController].signal,\n })\n\n if (init?.signal) {\n if (init.signal.aborted) {\n this.close()\n return\n }\n\n init.signal.addEventListener('abort', () => this.close(), {\n once: true,\n signal: this[kAbortController].signal,\n })\n }\n\n this.connect()\n }\n\n get onopen(): EventHandler<Event> | null {\n return this[kOnOpen]\n }\n\n set onopen(handler: EventHandler<Event>) {\n if (this[kOnOpen]) {\n this.removeEventListener('open', this[kOnOpen])\n }\n this[kOnOpen] = handler.bind(this)\n this.addEventListener('open', this[kOnOpen])\n }\n\n get onmessage(): EventHandler<MessageEvent> | null {\n return this[kOnMessage]\n }\n set onmessage(handler: EventHandler<MessageEvent>) {\n if (this[kOnMessage]) {\n this.removeEventListener('message', { handleEvent: this[kOnMessage] })\n }\n this[kOnMessage] = handler.bind(this)\n this.addEventListener('message', { handleEvent: this[kOnMessage] })\n }\n\n get onerror(): EventHandler<Event> | null {\n return this[kOnError]\n }\n set onerror(handler: EventHandler<Event>) {\n if (this[kOnError]) {\n this.removeEventListener('error', { handleEvent: this[kOnError] })\n }\n this[kOnError] = handler.bind(this)\n this.addEventListener('error', { handleEvent: this[kOnError] })\n }\n\n public addEventListener<K extends keyof EventSourceEventMap>(\n type: K,\n listener: EventHandler<EventSourceEventMap[K]>,\n options?: boolean | AddEventListenerOptions,\n ): void\n public addEventListener(\n type: string,\n listener: EventHandler<MessageEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void\n public addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void\n\n public addEventListener(\n type: string,\n listener: EventHandler<MessageEvent> | EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void {\n super.addEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n )\n }\n\n public removeEventListener<K extends keyof EventSourceEventMap>(\n type: K,\n listener: (this: EventSource, ev: EventSourceEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ): void\n public removeEventListener(\n type: string,\n listener: (this: EventSource, event: MessageEvent) => any,\n options?: boolean | EventListenerOptions,\n ): void\n public removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void\n\n public removeEventListener(\n type: string,\n listener: EventHandler<MessageEvent> | EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void {\n super.removeEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n )\n }\n\n public dispatchEvent(event: Event): boolean {\n return super.dispatchEvent(event)\n }\n\n public close(): void {\n this[kAbortController].abort()\n this.readyState = this.CLOSED\n }\n\n private async connect() {\n await fetch(this[kRequest])\n .then((response) => {\n this.processResponse(response)\n })\n .catch(() => {\n // Fail the connection on request errors instead of\n // throwing a generic \"Failed to fetch\" error.\n this.failConnection()\n })\n }\n\n private processResponse(response: Response): void {\n if (!response.body) {\n this.failConnection()\n return\n }\n\n if (isNetworkError(response)) {\n this.reestablishConnection()\n return\n }\n\n if (\n response.status !== 200 ||\n response.headers.get('content-type') !== 'text/event-stream'\n ) {\n this.failConnection()\n return\n }\n\n this.announceConnection()\n this.interpretResponseBody(response)\n }\n\n private announceConnection(): void {\n queueMicrotask(() => {\n if (this.readyState !== this.CLOSED) {\n this.readyState = this.OPEN\n this.dispatchEvent(new Event('open'))\n }\n })\n }\n\n private interpretResponseBody(response: Response): void {\n const parsingStream = new EventSourceParsingStream({\n message: (message) => {\n if (message.id) {\n this[kLastEventId] = message.id\n }\n\n const messageEvent = new MessageEvent(\n message.event ? message.event : 'message',\n {\n data: message.data,\n origin: this[kRequest].url,\n lastEventId: this[kLastEventId],\n cancelable: true,\n },\n )\n\n this[kOnAnyMessage]?.(messageEvent)\n this.dispatchEvent(messageEvent)\n },\n retry: (reconnectionTime) => {\n this[kReconnectionTime] = reconnectionTime\n },\n abort: () => {\n throw new Error('Stream abort is not implemented')\n },\n close: () => {\n this.failConnection()\n },\n })\n\n response\n .body!.pipeTo(parsingStream)\n .then(() => {\n this.processResponseEndOfBody(response)\n })\n .catch(() => {\n this.failConnection()\n })\n }\n\n private processResponseEndOfBody(response: Response): void {\n if (!isNetworkError(response)) {\n this.reestablishConnection()\n }\n }\n\n private async reestablishConnection(): Promise<void> {\n queueMicrotask(() => {\n if (this.readyState === this.CLOSED) {\n return\n }\n\n this.readyState = this.CONNECTING\n this.dispatchEvent(new Event('error'))\n })\n\n const signal = this[kAbortController].signal\n\n if (signal.aborted) {\n return\n }\n\n const aborted = new DeferredPromise<void>()\n const onAbort = () => aborted.resolve()\n signal.addEventListener('abort', onAbort, { once: true })\n\n await Promise.race([delay(this[kReconnectionTime]), aborted]).finally(\n () => {\n signal.removeEventListener('abort', onAbort)\n },\n )\n\n if (signal.aborted) {\n return\n }\n\n queueMicrotask(async () => {\n if (this.readyState !== this.CONNECTING) {\n return\n }\n\n if (this[kLastEventId] !== '') {\n this[kRequest].headers.set('last-event-id', this[kLastEventId])\n }\n\n await this.connect()\n })\n }\n\n private failConnection(): void {\n queueMicrotask(() => {\n if (this.readyState !== this.CLOSED) {\n this.readyState = this.CLOSED\n this.dispatchEvent(new Event('error'))\n }\n })\n }\n}\n\n/**\n * Checks if the given `Response` instance is a network error.\n * @see https://fetch.spec.whatwg.org/#concept-network-error\n */\nfunction isNetworkError(response: Response): boolean {\n return (\n response.type === 'error' &&\n response.status === 0 &&\n response.statusText === '' &&\n Array.from(response.headers.entries()).length === 0 &&\n response.body === null\n )\n}\n\nconst enum ControlCharacters {\n NewLine = 10,\n CarriageReturn = 13,\n Space = 32,\n Colon = 58,\n}\n\ninterface EventSourceMessage {\n id?: string\n event?: string\n data?: string\n}\n\nclass EventSourceParsingStream extends WritableStream {\n private decoder: TextDecoder\n\n private buffer?: Uint8Array\n private position: number\n private fieldLength?: number\n private discardTrailingNewline = false\n\n private message: EventSourceMessage = {\n id: undefined,\n event: undefined,\n data: undefined,\n }\n\n constructor(\n private underlyingSink: {\n message: (message: EventSourceMessage) => void\n retry?: (reconnectionTime: number) => void\n abort?: (reason: any) => void\n close?: () => void\n },\n ) {\n super({\n write: (chunk) => {\n this.processResponseBodyChunk(chunk)\n },\n abort: (reason) => {\n this.underlyingSink.abort?.(reason)\n },\n close: () => {\n this.underlyingSink.close?.()\n },\n })\n\n this.decoder = new TextDecoder()\n this.position = 0\n }\n\n private resetMessage(): void {\n this.message = {\n id: undefined,\n event: undefined,\n data: undefined,\n }\n }\n\n private processResponseBodyChunk(chunk: Uint8Array): void {\n if (this.buffer == null) {\n this.buffer = chunk\n this.position = 0\n this.fieldLength = -1\n } else {\n const nextBuffer = new Uint8Array(this.buffer.length + chunk.length)\n nextBuffer.set(this.buffer)\n nextBuffer.set(chunk, this.buffer.length)\n this.buffer = nextBuffer\n }\n\n const bufferLength = this.buffer.length\n let lineStart = 0\n\n while (this.position < bufferLength) {\n if (this.discardTrailingNewline) {\n if (this.buffer[this.position] === ControlCharacters.NewLine) {\n lineStart = ++this.position\n }\n\n this.discardTrailingNewline = false\n }\n\n let lineEnd = -1\n\n for (; this.position < bufferLength && lineEnd === -1; ++this.position) {\n switch (this.buffer[this.position]) {\n case ControlCharacters.Colon: {\n if (this.fieldLength === -1) {\n this.fieldLength = this.position - lineStart\n }\n break\n }\n\n case ControlCharacters.CarriageReturn: {\n this.discardTrailingNewline = true\n break\n }\n\n case ControlCharacters.NewLine: {\n lineEnd = this.position\n break\n }\n }\n }\n\n if (lineEnd === -1) {\n break\n }\n\n this.processLine(\n this.buffer.subarray(lineStart, lineEnd),\n this.fieldLength!,\n )\n\n lineStart = this.position\n this.fieldLength = -1\n }\n\n if (lineStart === bufferLength) {\n this.buffer = undefined\n } else if (lineStart !== 0) {\n this.buffer = this.buffer.subarray(lineStart)\n this.position -= lineStart\n }\n }\n\n private processLine(line: Uint8Array, fieldLength: number): void {\n // New line indicates the end of the message. Dispatch it.\n if (line.length === 0) {\n // Prevent dispatching the message if the data is an empty string.\n // That is a no-op per spec.\n if (this.message.data === undefined) {\n this.message.event = undefined\n return\n }\n\n this.underlyingSink.message(this.message)\n this.resetMessage()\n return\n }\n\n // Otherwise, keep accumulating message fields until the new line.\n if (fieldLength > 0) {\n const field = this.decoder.decode(line.subarray(0, fieldLength))\n const valueOffset =\n fieldLength +\n (line[fieldLength + 1] === ControlCharacters.Space ? 2 : 1)\n const value = this.decoder.decode(line.subarray(valueOffset))\n\n switch (field) {\n case 'data': {\n this.message.data = this.message.data\n ? this.message.data + '\\n' + value\n : value\n break\n }\n\n case 'event': {\n this.message.event = value\n break\n }\n\n case 'id': {\n this.message.id = value\n break\n }\n\n case 'retry': {\n /**\n * Apply the retry immediately. Don't buffer onto the current message.\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation\n */\n if (/^\\d+$/.test(value)) {\n this.underlyingSink.retry?.(parseInt(value, 10))\n }\n break\n }\n }\n }\n }\n}\n\ninterface EventStreamMessage {\n id?: string\n event: string\n data?: unknown\n frames: Array<string>\n}\n\ninterface EventStream<EventMap extends EventMapConstraint> {\n client: ServerSentEventClient<EventMap>\n server: ServerSentEventServer\n response: Response\n}\n\n/**\n * Create an event stream out of the given Fetch API `Request`.\n * Returns the following properties:\n * - `client`, to operate on the intercepted request;\n * - `server`, to establish and manage the actual server connection;\n * - `response`, a `Response` to use as the mock response's body.\n *\n * @example\n * http.post('/resource', ({ request }) => {\n * const { client, server, response } = createEventStream(request)\n * client.send({ data: 'hello world' })\n * return response\n * })\n */\nfunction createEventStream<EventMap extends EventMapConstraint>(\n request: Request,\n): EventStream<EventMap> {\n invariant(\n !request.signal.aborted,\n 'Failed to call \"createEventStream\" on the \"%s %s\" request: request aborted',\n request.method,\n request.url,\n )\n\n const { readable, writable } = new TransformStream()\n\n const client = new ServerSentEventClient<EventMap>(writable)\n const server = new ServerSentEventServer({\n request,\n client,\n })\n\n const response = new Response(readable, SSE_RESPONSE_INIT)\n\n request.signal.addEventListener(\n 'abort',\n () => {\n client.close()\n },\n { once: true },\n )\n\n return {\n client,\n server,\n response,\n }\n}\n"],"mappings":"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","names":["ControlCharacters"]}