msw 2.14.7 → 2.15.0
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.
- package/lib/browser/index.js +1 -1
- package/lib/browser/index.mjs +1 -1
- package/lib/core/{HttpResponse-BTyqrRB6.d.mts → HttpResponse-BE_Y2Ak9.d.mts} +18 -0
- package/lib/core/{HttpResponse-BXyXQFMJ.d.ts → HttpResponse-DL-P1EeG.d.ts} +18 -0
- package/lib/core/HttpResponse.d.mts +1 -1
- package/lib/core/HttpResponse.d.ts +1 -1
- package/lib/core/experimental/compat.d.mts +1 -1
- package/lib/core/experimental/compat.d.ts +1 -1
- package/lib/core/experimental/define-network.d.mts +1 -1
- package/lib/core/experimental/define-network.d.ts +1 -1
- package/lib/core/experimental/frames/http-frame.d.mts +1 -1
- package/lib/core/experimental/frames/http-frame.d.ts +1 -1
- package/lib/core/experimental/frames/network-frame.d.mts +1 -1
- package/lib/core/experimental/frames/network-frame.d.ts +1 -1
- package/lib/core/experimental/frames/websocket-frame.d.mts +1 -1
- package/lib/core/experimental/frames/websocket-frame.d.ts +1 -1
- package/lib/core/experimental/handlers-controller.d.mts +1 -1
- package/lib/core/experimental/handlers-controller.d.ts +1 -1
- package/lib/core/experimental/index.d.mts +1 -1
- package/lib/core/experimental/index.d.ts +1 -1
- package/lib/core/experimental/on-unhandled-frame.d.mts +1 -1
- package/lib/core/experimental/on-unhandled-frame.d.ts +1 -1
- package/lib/core/experimental/setup-api.d.mts +1 -1
- package/lib/core/experimental/setup-api.d.ts +1 -1
- package/lib/core/experimental/sources/interceptor-source.d.mts +1 -1
- package/lib/core/experimental/sources/interceptor-source.d.ts +1 -1
- package/lib/core/experimental/sources/network-source.d.mts +1 -1
- package/lib/core/experimental/sources/network-source.d.ts +1 -1
- package/lib/core/getResponse.d.mts +1 -1
- package/lib/core/getResponse.d.ts +1 -1
- package/lib/core/graphql.d.mts +1 -1
- package/lib/core/graphql.d.ts +1 -1
- package/lib/core/handlers/GraphQLHandler.d.mts +1 -1
- package/lib/core/handlers/GraphQLHandler.d.ts +1 -1
- package/lib/core/handlers/HttpHandler.d.mts +1 -1
- package/lib/core/handlers/HttpHandler.d.ts +1 -1
- package/lib/core/handlers/RequestHandler.d.mts +1 -1
- package/lib/core/handlers/RequestHandler.d.ts +1 -1
- package/lib/core/handlers/RequestHandler.js +88 -23
- package/lib/core/handlers/RequestHandler.js.map +1 -1
- package/lib/core/handlers/RequestHandler.mjs +88 -23
- package/lib/core/handlers/RequestHandler.mjs.map +1 -1
- package/lib/core/http.d.mts +1 -1
- package/lib/core/http.d.ts +1 -1
- package/lib/core/index.d.mts +1 -1
- package/lib/core/index.d.ts +1 -1
- package/lib/core/passthrough.d.mts +1 -1
- package/lib/core/passthrough.d.ts +1 -1
- package/lib/core/sse.d.mts +2 -2
- package/lib/core/sse.d.ts +2 -2
- package/lib/core/sse.js +66 -48
- package/lib/core/sse.js.map +1 -1
- package/lib/core/sse.mjs +65 -47
- package/lib/core/sse.mjs.map +1 -1
- package/lib/core/utils/HttpResponse/decorators.d.mts +8 -3
- package/lib/core/utils/HttpResponse/decorators.d.ts +8 -3
- package/lib/core/utils/HttpResponse/decorators.js +13 -0
- package/lib/core/utils/HttpResponse/decorators.js.map +1 -1
- package/lib/core/utils/HttpResponse/decorators.mjs +13 -0
- package/lib/core/utils/HttpResponse/decorators.mjs.map +1 -1
- package/lib/core/utils/executeHandlers.d.mts +1 -1
- package/lib/core/utils/executeHandlers.d.ts +1 -1
- package/lib/core/utils/handleRequest.d.mts +1 -1
- package/lib/core/utils/handleRequest.d.ts +1 -1
- package/lib/core/utils/internal/attachSiblingHandlers.d.mts +1 -1
- package/lib/core/utils/internal/attachSiblingHandlers.d.ts +1 -1
- package/lib/core/utils/internal/isHandlerKind.d.mts +1 -1
- package/lib/core/utils/internal/isHandlerKind.d.ts +1 -1
- package/lib/core/utils/internal/observe-response-body-stream.d.mts +18 -0
- package/lib/core/utils/internal/observe-response-body-stream.d.ts +18 -0
- package/lib/core/utils/internal/observe-response-body-stream.js +64 -0
- package/lib/core/utils/internal/observe-response-body-stream.js.map +1 -0
- package/lib/core/utils/internal/observe-response-body-stream.mjs +44 -0
- package/lib/core/utils/internal/observe-response-body-stream.mjs.map +1 -0
- package/lib/core/utils/internal/parseGraphQLRequest.d.mts +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.d.ts +1 -1
- package/lib/core/utils/internal/parseMultipartData.d.mts +1 -1
- package/lib/core/utils/internal/parseMultipartData.d.ts +1 -1
- package/lib/core/ws/handleWebSocketEvent.d.mts +1 -1
- package/lib/core/ws/handleWebSocketEvent.d.ts +1 -1
- package/lib/iife/index.js +270 -137
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +21 -9
- package/package.json +2 -2
- package/src/core/handlers/HttpHandler.test.ts +89 -0
- package/src/core/handlers/RequestHandler.ts +142 -32
- package/src/core/sse.ts +85 -53
- package/src/core/utils/HttpResponse/decorators.ts +23 -2
- package/src/core/utils/internal/observe-response-body-stream.test.ts +64 -0
- package/src/core/utils/internal/observe-response-body-stream.ts +77 -0
- package/src/mockServiceWorker.js +19 -7
package/lib/core/sse.js
CHANGED
|
@@ -23,7 +23,7 @@ __export(sse_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(sse_exports);
|
|
24
24
|
var import_outvariant = require("outvariant");
|
|
25
25
|
var import_deferred_promise = require("@open-draft/deferred-promise");
|
|
26
|
-
var
|
|
26
|
+
var import_rettime = require("rettime");
|
|
27
27
|
var import_HttpHandler = require("./handlers/HttpHandler");
|
|
28
28
|
var import_delay = require("./delay");
|
|
29
29
|
var import_getTimestamp = require("./utils/logging/getTimestamp");
|
|
@@ -52,16 +52,17 @@ class ServerSentEventHandler extends import_HttpHandler.HttpHandler {
|
|
|
52
52
|
const { client, server, response } = createEventStream(
|
|
53
53
|
info.request
|
|
54
54
|
);
|
|
55
|
-
const emitter = new
|
|
55
|
+
const emitter = new import_rettime.Emitter();
|
|
56
56
|
client[kClientEmitter] = emitter;
|
|
57
57
|
if (this.#loggableRequests.has(info.request)) {
|
|
58
58
|
this.#attachClientLogger(info.request, emitter);
|
|
59
59
|
}
|
|
60
|
-
await resolver(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
await resolver(
|
|
61
|
+
Object.assign(info, {
|
|
62
|
+
client,
|
|
63
|
+
server
|
|
64
|
+
})
|
|
65
|
+
);
|
|
65
66
|
return response;
|
|
66
67
|
});
|
|
67
68
|
this.#loggableRequests = /* @__PURE__ */ new WeakSet();
|
|
@@ -84,21 +85,20 @@ class ServerSentEventHandler extends import_HttpHandler.HttpHandler {
|
|
|
84
85
|
}
|
|
85
86
|
return matches;
|
|
86
87
|
}
|
|
87
|
-
async log(
|
|
88
|
+
async log(args) {
|
|
89
|
+
args.response.body?.cancel();
|
|
88
90
|
return;
|
|
89
91
|
}
|
|
90
92
|
#attachClientLogger(request, emitter) {
|
|
91
93
|
const publicUrl = (0, import_toPublicUrl.toPublicUrl)(request.url);
|
|
92
|
-
emitter.on("message", (
|
|
94
|
+
emitter.on("message", ({ data }) => {
|
|
93
95
|
console.groupCollapsed(
|
|
94
|
-
import_devUtils.devUtils.formatMessage(
|
|
95
|
-
`${(0, import_getTimestamp.getTimestamp)()} SSE %s %c\u21E3%c ${payload.event}`
|
|
96
|
-
),
|
|
96
|
+
import_devUtils.devUtils.formatMessage(`${(0, import_getTimestamp.getTimestamp)()} SSE %s %c\u21E3%c ${data.event}`),
|
|
97
97
|
publicUrl,
|
|
98
98
|
`color:${import_attachWebSocketLogger.colors.mocked}`,
|
|
99
99
|
"color:inherit"
|
|
100
100
|
);
|
|
101
|
-
console.log(
|
|
101
|
+
console.log(data.frames);
|
|
102
102
|
console.groupEnd();
|
|
103
103
|
});
|
|
104
104
|
emitter.on("error", () => {
|
|
@@ -127,10 +127,12 @@ const kClientEmitter = /* @__PURE__ */ Symbol.for("kClientEmitter");
|
|
|
127
127
|
class ServerSentEventClient {
|
|
128
128
|
[kClientEmitter];
|
|
129
129
|
#encoder;
|
|
130
|
-
#
|
|
131
|
-
|
|
130
|
+
#controller;
|
|
131
|
+
#closed;
|
|
132
|
+
constructor(controller) {
|
|
132
133
|
this.#encoder = new TextEncoder();
|
|
133
|
-
this.#
|
|
134
|
+
this.#controller = controller;
|
|
135
|
+
this.#closed = new import_deferred_promise.DeferredPromise();
|
|
134
136
|
}
|
|
135
137
|
/**
|
|
136
138
|
* Sends the given payload to the intercepted `EventSource`.
|
|
@@ -173,35 +175,44 @@ class ServerSentEventClient {
|
|
|
173
175
|
* error.
|
|
174
176
|
*/
|
|
175
177
|
error() {
|
|
176
|
-
this.#
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
this[kClientEmitter]?.emit("error");
|
|
178
|
+
if (this.#closed.state !== "pending") {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
this.#controller.error();
|
|
182
|
+
this.#closed.resolve();
|
|
183
|
+
this[kClientEmitter]?.emit(new import_rettime.TypedEvent("error"));
|
|
183
184
|
}
|
|
184
185
|
/**
|
|
185
186
|
* Closes the underlying `EventSource`, closing the connection.
|
|
186
187
|
*/
|
|
187
188
|
close() {
|
|
188
|
-
this.#
|
|
189
|
+
if (this.#closed.state !== "pending") {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
this.#controller.close();
|
|
194
|
+
this.#closed.resolve();
|
|
195
|
+
} catch {
|
|
196
|
+
}
|
|
197
|
+
this[kClientEmitter]?.emit(new import_rettime.TypedEvent("close"));
|
|
198
|
+
}
|
|
199
|
+
#enqueue(chunk) {
|
|
200
|
+
if (this.#closed.state !== "pending") {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
this.#controller.enqueue(chunk);
|
|
205
|
+
} catch (error) {
|
|
189
206
|
console.error(error);
|
|
190
207
|
import_devUtils.devUtils.error(
|
|
191
|
-
"Failed to
|
|
208
|
+
"Failed to write to server-side EventSource. Please see the original error above."
|
|
192
209
|
);
|
|
193
|
-
}
|
|
194
|
-
this[kClientEmitter]?.emit("close");
|
|
210
|
+
}
|
|
195
211
|
}
|
|
196
212
|
#sendRetry(retry) {
|
|
197
|
-
this.#
|
|
213
|
+
this.#enqueue(this.#encoder.encode(`retry:${retry}
|
|
198
214
|
|
|
199
|
-
`))
|
|
200
|
-
console.error(error);
|
|
201
|
-
import_devUtils.devUtils.error(
|
|
202
|
-
"Failed to send a retry packet to server-side EventSource. Please see the original error above."
|
|
203
|
-
);
|
|
204
|
-
});
|
|
215
|
+
`));
|
|
205
216
|
}
|
|
206
217
|
#sendMessage(message) {
|
|
207
218
|
const frames = [];
|
|
@@ -217,18 +228,17 @@ class ServerSentEventClient {
|
|
|
217
228
|
}
|
|
218
229
|
}
|
|
219
230
|
frames.push("", "");
|
|
220
|
-
this.#
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
});
|
|
231
|
+
this.#enqueue(this.#encoder.encode(frames.join("\n")));
|
|
232
|
+
this[kClientEmitter]?.emit(
|
|
233
|
+
new import_rettime.TypedEvent("message", {
|
|
234
|
+
data: {
|
|
235
|
+
id: message.id,
|
|
236
|
+
event: message.event?.toString() || "message",
|
|
237
|
+
data: message.data,
|
|
238
|
+
frames
|
|
239
|
+
}
|
|
240
|
+
})
|
|
241
|
+
);
|
|
232
242
|
}
|
|
233
243
|
}
|
|
234
244
|
class ServerSentEventServer {
|
|
@@ -649,8 +659,16 @@ function createEventStream(request) {
|
|
|
649
659
|
request.method,
|
|
650
660
|
request.url
|
|
651
661
|
);
|
|
652
|
-
|
|
653
|
-
const
|
|
662
|
+
let controller;
|
|
663
|
+
const readable = new ReadableStream({
|
|
664
|
+
start(defaultController) {
|
|
665
|
+
controller = defaultController;
|
|
666
|
+
},
|
|
667
|
+
cancel() {
|
|
668
|
+
client.close();
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
const client = new ServerSentEventClient(controller);
|
|
654
672
|
const server = new ServerSentEventServer({
|
|
655
673
|
request,
|
|
656
674
|
client
|
package/lib/core/sse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 #loggableRequests: WeakSet<Request>\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 /**\n * @note Scope the emitter to this connection so its logging\n * listeners don't accumulate on the handler across connections.\n */\n const emitter = new Emitter<ServerSentEventClientEventMap>()\n client[kClientEmitter] = emitter\n\n if (this.#loggableRequests.has(info.request)) {\n this.#attachClientLogger(info.request, emitter)\n }\n\n await resolver({\n ...info,\n client,\n server,\n })\n\n return response\n })\n\n this.#loggableRequests = new WeakSet()\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 // Defer attaching the client logger until the resolver runs\n // and creates a connection-scoped emitter for this request.\n this.#loggableRequests.add(args.request)\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"]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/sse.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { Emitter, TypedEvent } from 'rettime'\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 #loggableRequests: WeakSet<Request>\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 /**\n * @note Scope the emitter to this connection so its logging\n * listeners don't accumulate on the handler across connections.\n */\n const emitter = new Emitter<ServerSentEventClientEventMap>()\n client[kClientEmitter] = emitter\n\n if (this.#loggableRequests.has(info.request)) {\n this.#attachClientLogger(info.request, emitter)\n }\n\n /**\n * @note Extend the resolver info via assignment instead of a spread.\n * Spreading the info would invoke its lazy `finalize` getter,\n * initializing the finalize machinery for resolvers that never use it.\n */\n await resolver(\n Object.assign(info, {\n client,\n server,\n }),\n )\n\n return response\n })\n\n this.#loggableRequests = new WeakSet()\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 // Defer attaching the client logger until the resolver runs\n // and creates a connection-scoped emitter for this request.\n this.#loggableRequests.add(args.request)\n }\n\n return matches\n }\n\n async log(args: { request: Request; response: Response }): Promise<void> {\n /**\n * @note Cancel the response stream because it's not needed for logging.\n * Otherwise, this cloned response remains unconsumed and its original\n * doesn't propagate stream cancelations at all.\n */\n args.response.body?.cancel()\n\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', ({ data }) => {\n console.groupCollapsed(\n devUtils.formatMessage(`${getTimestamp()} SSE %s %c⇣%c ${data.event}`),\n publicUrl,\n `color:${colors.mocked}`,\n 'color:inherit',\n )\n console.log(data.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: TypedEvent<EventStreamMessage>\n error: TypedEvent\n close: TypedEvent\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 #controller: ReadableStreamDefaultController<Uint8Array>\n #closed: DeferredPromise<void>\n\n constructor(controller: ReadableStreamDefaultController<Uint8Array>) {\n this.#encoder = new TextEncoder()\n this.#controller = controller\n this.#closed = new DeferredPromise()\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 if (this.#closed.state !== 'pending') {\n return\n }\n\n this.#controller.error()\n this.#closed.resolve()\n this[kClientEmitter]?.emit(new TypedEvent('error'))\n }\n\n /**\n * Closes the underlying `EventSource`, closing the connection.\n */\n public close(): void {\n if (this.#closed.state !== 'pending') {\n return\n }\n\n try {\n this.#controller.close()\n this.#closed.resolve()\n } catch {\n //\n }\n\n this[kClientEmitter]?.emit(new TypedEvent('close'))\n }\n\n #enqueue(chunk: Uint8Array): void {\n if (this.#closed.state !== 'pending') {\n return\n }\n\n try {\n this.#controller.enqueue(chunk)\n } catch (error) {\n console.error(error)\n devUtils.error(\n 'Failed to write to server-side EventSource. Please see the original error above.',\n )\n }\n }\n\n #sendRetry(retry: number): void {\n this.#enqueue(this.#encoder.encode(`retry:${retry}\\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.#enqueue(this.#encoder.encode(frames.join('\\n')))\n\n this[kClientEmitter]?.emit(\n new TypedEvent('message', {\n data: {\n id: message.id,\n event: message.event?.toString() || 'message',\n data: message.data,\n frames,\n },\n }),\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 let controller!: ReadableStreamDefaultController<Uint8Array>\n\n const readable = new ReadableStream<Uint8Array>({\n start(defaultController) {\n controller = defaultController\n },\n cancel() {\n client.close()\n },\n })\n\n const client = new ServerSentEventClient<EventMap>(controller)\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"]}
|
package/lib/core/sse.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { invariant } from "outvariant";
|
|
2
2
|
import { DeferredPromise } from "@open-draft/deferred-promise";
|
|
3
|
-
import { Emitter } from "
|
|
3
|
+
import { Emitter, TypedEvent } from "rettime";
|
|
4
4
|
import {
|
|
5
5
|
HttpHandler
|
|
6
6
|
} from './handlers/HttpHandler.mjs';
|
|
@@ -36,11 +36,12 @@ class ServerSentEventHandler extends HttpHandler {
|
|
|
36
36
|
if (this.#loggableRequests.has(info.request)) {
|
|
37
37
|
this.#attachClientLogger(info.request, emitter);
|
|
38
38
|
}
|
|
39
|
-
await resolver(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
await resolver(
|
|
40
|
+
Object.assign(info, {
|
|
41
|
+
client,
|
|
42
|
+
server
|
|
43
|
+
})
|
|
44
|
+
);
|
|
44
45
|
return response;
|
|
45
46
|
});
|
|
46
47
|
this.#loggableRequests = /* @__PURE__ */ new WeakSet();
|
|
@@ -63,21 +64,20 @@ class ServerSentEventHandler extends HttpHandler {
|
|
|
63
64
|
}
|
|
64
65
|
return matches;
|
|
65
66
|
}
|
|
66
|
-
async log(
|
|
67
|
+
async log(args) {
|
|
68
|
+
args.response.body?.cancel();
|
|
67
69
|
return;
|
|
68
70
|
}
|
|
69
71
|
#attachClientLogger(request, emitter) {
|
|
70
72
|
const publicUrl = toPublicUrl(request.url);
|
|
71
|
-
emitter.on("message", (
|
|
73
|
+
emitter.on("message", ({ data }) => {
|
|
72
74
|
console.groupCollapsed(
|
|
73
|
-
devUtils.formatMessage(
|
|
74
|
-
`${getTimestamp()} SSE %s %c\u21E3%c ${payload.event}`
|
|
75
|
-
),
|
|
75
|
+
devUtils.formatMessage(`${getTimestamp()} SSE %s %c\u21E3%c ${data.event}`),
|
|
76
76
|
publicUrl,
|
|
77
77
|
`color:${colors.mocked}`,
|
|
78
78
|
"color:inherit"
|
|
79
79
|
);
|
|
80
|
-
console.log(
|
|
80
|
+
console.log(data.frames);
|
|
81
81
|
console.groupEnd();
|
|
82
82
|
});
|
|
83
83
|
emitter.on("error", () => {
|
|
@@ -106,10 +106,12 @@ const kClientEmitter = /* @__PURE__ */ Symbol.for("kClientEmitter");
|
|
|
106
106
|
class ServerSentEventClient {
|
|
107
107
|
[kClientEmitter];
|
|
108
108
|
#encoder;
|
|
109
|
-
#
|
|
110
|
-
|
|
109
|
+
#controller;
|
|
110
|
+
#closed;
|
|
111
|
+
constructor(controller) {
|
|
111
112
|
this.#encoder = new TextEncoder();
|
|
112
|
-
this.#
|
|
113
|
+
this.#controller = controller;
|
|
114
|
+
this.#closed = new DeferredPromise();
|
|
113
115
|
}
|
|
114
116
|
/**
|
|
115
117
|
* Sends the given payload to the intercepted `EventSource`.
|
|
@@ -152,35 +154,44 @@ class ServerSentEventClient {
|
|
|
152
154
|
* error.
|
|
153
155
|
*/
|
|
154
156
|
error() {
|
|
155
|
-
this.#
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
this[kClientEmitter]?.emit("error");
|
|
157
|
+
if (this.#closed.state !== "pending") {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
this.#controller.error();
|
|
161
|
+
this.#closed.resolve();
|
|
162
|
+
this[kClientEmitter]?.emit(new TypedEvent("error"));
|
|
162
163
|
}
|
|
163
164
|
/**
|
|
164
165
|
* Closes the underlying `EventSource`, closing the connection.
|
|
165
166
|
*/
|
|
166
167
|
close() {
|
|
167
|
-
this.#
|
|
168
|
+
if (this.#closed.state !== "pending") {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
this.#controller.close();
|
|
173
|
+
this.#closed.resolve();
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
this[kClientEmitter]?.emit(new TypedEvent("close"));
|
|
177
|
+
}
|
|
178
|
+
#enqueue(chunk) {
|
|
179
|
+
if (this.#closed.state !== "pending") {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
this.#controller.enqueue(chunk);
|
|
184
|
+
} catch (error) {
|
|
168
185
|
console.error(error);
|
|
169
186
|
devUtils.error(
|
|
170
|
-
"Failed to
|
|
187
|
+
"Failed to write to server-side EventSource. Please see the original error above."
|
|
171
188
|
);
|
|
172
|
-
}
|
|
173
|
-
this[kClientEmitter]?.emit("close");
|
|
189
|
+
}
|
|
174
190
|
}
|
|
175
191
|
#sendRetry(retry) {
|
|
176
|
-
this.#
|
|
192
|
+
this.#enqueue(this.#encoder.encode(`retry:${retry}
|
|
177
193
|
|
|
178
|
-
`))
|
|
179
|
-
console.error(error);
|
|
180
|
-
devUtils.error(
|
|
181
|
-
"Failed to send a retry packet to server-side EventSource. Please see the original error above."
|
|
182
|
-
);
|
|
183
|
-
});
|
|
194
|
+
`));
|
|
184
195
|
}
|
|
185
196
|
#sendMessage(message) {
|
|
186
197
|
const frames = [];
|
|
@@ -196,18 +207,17 @@ class ServerSentEventClient {
|
|
|
196
207
|
}
|
|
197
208
|
}
|
|
198
209
|
frames.push("", "");
|
|
199
|
-
this.#
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
});
|
|
210
|
+
this.#enqueue(this.#encoder.encode(frames.join("\n")));
|
|
211
|
+
this[kClientEmitter]?.emit(
|
|
212
|
+
new TypedEvent("message", {
|
|
213
|
+
data: {
|
|
214
|
+
id: message.id,
|
|
215
|
+
event: message.event?.toString() || "message",
|
|
216
|
+
data: message.data,
|
|
217
|
+
frames
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
);
|
|
211
221
|
}
|
|
212
222
|
}
|
|
213
223
|
class ServerSentEventServer {
|
|
@@ -628,8 +638,16 @@ function createEventStream(request) {
|
|
|
628
638
|
request.method,
|
|
629
639
|
request.url
|
|
630
640
|
);
|
|
631
|
-
|
|
632
|
-
const
|
|
641
|
+
let controller;
|
|
642
|
+
const readable = new ReadableStream({
|
|
643
|
+
start(defaultController) {
|
|
644
|
+
controller = defaultController;
|
|
645
|
+
},
|
|
646
|
+
cancel() {
|
|
647
|
+
client.close();
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
const client = new ServerSentEventClient(controller);
|
|
633
651
|
const server = new ServerSentEventServer({
|
|
634
652
|
request,
|
|
635
653
|
client
|