msw 2.14.7 → 3.0.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/README.md +8 -0
- package/cli/init.js +12 -9
- package/cli/invariant.js +2 -2
- package/lib/_chunks/attach-sibling-handlers.js +360 -0
- package/lib/_chunks/attach-sibling-handlers.js.map +1 -0
- package/lib/_chunks/colors.js +18 -0
- package/lib/_chunks/colors.js.map +1 -0
- package/lib/_chunks/cookie-store.js +348 -0
- package/lib/_chunks/cookie-store.js.map +1 -0
- package/lib/_chunks/execute-handlers.js +29 -0
- package/lib/_chunks/execute-handlers.js.map +1 -0
- package/lib/_chunks/handlers-controller.d.ts +262 -0
- package/lib/_chunks/has-ref-counted.js +9 -0
- package/lib/_chunks/has-ref-counted.js.map +1 -0
- package/lib/_chunks/http-handler.d.ts +72 -0
- package/lib/_chunks/http-handler.js +182 -0
- package/lib/_chunks/http-handler.js.map +1 -0
- package/lib/_chunks/http-response.js +137 -0
- package/lib/_chunks/http-response.js.map +1 -0
- package/lib/{core → _chunks}/http.d.ts +15 -18
- package/lib/_chunks/http.js +30 -0
- package/lib/_chunks/http.js.map +1 -0
- package/lib/_chunks/interceptor-source.d.ts +163 -0
- package/lib/_chunks/interceptor-source.js +756 -0
- package/lib/_chunks/interceptor-source.js.map +1 -0
- package/lib/_chunks/is-object.js +11 -0
- package/lib/_chunks/is-object.js.map +1 -0
- package/lib/_chunks/match-request-url.d.ts +14 -0
- package/lib/_chunks/request-handler.d.ts +295 -0
- package/lib/_chunks/request-handler.js +369 -0
- package/lib/_chunks/request-handler.js.map +1 -0
- package/lib/_chunks/shared-options.d.ts +20 -0
- package/lib/_chunks/sse.d.ts +95 -0
- package/lib/_chunks/sse.js +599 -0
- package/lib/_chunks/sse.js.map +1 -0
- package/lib/_chunks/symbols.js +22 -0
- package/lib/_chunks/symbols.js.map +1 -0
- package/lib/_chunks/websocket-upgrade.js +46 -0
- package/lib/_chunks/websocket-upgrade.js.map +1 -0
- package/lib/_chunks/ws.d.ts +133 -0
- package/lib/_chunks/ws.js +293 -0
- package/lib/_chunks/ws.js.map +1 -0
- package/lib/browser/index.d.ts +225 -96
- package/lib/browser/index.js +555 -3694
- package/lib/browser/index.js.map +1 -1
- package/lib/core/experimental/index.d.ts +3 -17
- package/lib/core/experimental/index.js +2 -38
- package/lib/core/index.d.ts +15 -27
- package/lib/core/index.js +15 -64
- package/lib/graphql/index.d.ts +550 -0
- package/lib/graphql/index.js +1244 -0
- package/lib/graphql/index.js.map +1 -0
- package/lib/http/index.d.ts +4 -0
- package/lib/http/index.js +4 -0
- package/lib/iife/index.js +35857 -28289
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +204 -93
- package/lib/node/index.d.ts +79 -104
- package/lib/node/index.js +103 -201
- package/lib/node/index.js.map +1 -1
- package/lib/sse/index.d.ts +2 -0
- package/lib/sse/index.js +2 -0
- package/lib/{core → utils}/bypass.d.ts +5 -4
- package/lib/utils/bypass.js +41 -0
- package/lib/utils/bypass.js.map +1 -0
- package/lib/utils/delay.d.ts +15 -0
- package/lib/utils/delay.js +45 -0
- package/lib/utils/delay.js.map +1 -0
- package/lib/utils/get-clean-url-string.d.ts +9 -0
- package/lib/utils/get-clean-url-string.js +15 -0
- package/lib/utils/get-clean-url-string.js.map +1 -0
- package/lib/utils/get-response.d.ts +13 -0
- package/lib/utils/get-response.js +23 -0
- package/lib/utils/get-response.js.map +1 -0
- package/lib/utils/is-common-asset-request.d.ts +22 -0
- package/lib/utils/is-common-asset-request.js +31 -0
- package/lib/utils/is-common-asset-request.js.map +1 -0
- package/lib/utils/passthrough.d.ts +31 -0
- package/lib/utils/passthrough.js +41 -0
- package/lib/utils/passthrough.js.map +1 -0
- package/lib/vite/index.d.ts +44 -0
- package/lib/vite/index.js +90 -0
- package/lib/vite/index.js.map +1 -0
- package/lib/vite/runtime.d.ts +6 -0
- package/lib/vite/runtime.js +77 -0
- package/lib/vite/runtime.js.map +1 -0
- package/lib/ws/index.d.ts +4 -0
- package/lib/ws/index.js +4 -0
- package/package.json +93 -201
- package/src/browser/default-network-options.ts +31 -0
- package/src/browser/glossary.ts +11 -23
- package/src/browser/index.ts +5 -1
- package/src/browser/setup-worker.ts +15 -68
- package/src/browser/sources/fallback-http-source.ts +1 -1
- package/src/browser/sources/service-worker-source.ts +76 -69
- package/src/browser/tsconfig.browser.json +4 -2
- package/src/browser/utils/{deserializeRequest.ts → deserialize-request.ts} +3 -4
- package/src/browser/utils/{getAbsoluteWorkerUrl.test.ts → get-absolute-worker-url.test.ts} +3 -3
- package/src/browser/utils/get-worker-instance.ts +2 -2
- package/src/browser/utils/should-invalidate-worker.test.ts +11 -11
- package/src/browser/utils/should-invalidate-worker.ts +1 -1
- package/src/browser/utils/validate-worker-scope.ts +1 -1
- package/src/browser/utils/{workerChannel.ts → worker-channel.ts} +42 -20
- package/src/core/experimental/define-network.test.ts +43 -8
- package/src/core/experimental/define-network.ts +32 -13
- package/src/core/experimental/frames/http-frame.test.ts +15 -13
- package/src/core/experimental/frames/http-frame.ts +10 -9
- package/src/core/experimental/frames/websocket-frame.test.ts +129 -15
- package/src/core/experimental/frames/websocket-frame.ts +71 -20
- package/src/core/experimental/handlers-controller.test.ts +141 -34
- package/src/core/experimental/handlers-controller.ts +107 -30
- package/src/core/experimental/index.ts +1 -0
- package/src/core/experimental/on-unhandled-frame.test.ts +19 -19
- package/src/core/experimental/on-unhandled-frame.ts +7 -12
- package/src/core/experimental/request-utils.test.ts +4 -29
- package/src/core/experimental/request-utils.ts +0 -14
- package/src/core/experimental/sources/interceptor-source.ts +44 -29
- package/src/core/experimental/sources/network-source.test.ts +3 -3
- package/src/core/experimental/sources/network-source.ts +3 -3
- package/src/core/handlers/handler.ts +42 -0
- package/src/core/handlers/{RequestHandler.ts → request-handler.ts} +168 -73
- package/src/core/index.ts +35 -58
- package/src/core/shared-options.ts +21 -0
- package/src/core/type-utils.ts +18 -0
- package/src/core/utils/{cookieStore.ts → cookie-store.ts} +14 -9
- package/src/core/utils/{executeHandlers.ts → execute-handlers.ts} +2 -2
- package/src/core/utils/http-status-messages.ts +69 -0
- package/src/core/utils/internal/{attachSiblingHandlers.ts → attach-sibling-handlers.ts} +20 -0
- package/src/core/utils/internal/{devUtils.test.ts → dev-utils.test.ts} +3 -3
- package/src/core/utils/internal/{Disposable.ts → disposable.ts} +1 -1
- package/src/core/utils/internal/{getCallFrame.test.ts → get-call-frame.test.ts} +1 -1
- package/src/core/utils/internal/{getCallFrame.ts → get-call-frame.ts} +1 -1
- package/src/core/utils/internal/{hasRefCounted.test.ts → has-ref-counted.test.ts} +4 -4
- package/src/core/utils/internal/{hasRefCounted.ts → has-ref-counted.ts} +1 -1
- package/src/core/utils/internal/{isIterable.test.ts → is-iterable.test.ts} +1 -1
- package/src/core/utils/internal/is-iterable.ts +16 -0
- package/src/core/utils/internal/{isObject.test.ts → is-object.test.ts} +1 -1
- package/src/core/utils/internal/{isStringEqual.test.ts → is-string-equal.test.ts} +7 -7
- package/src/core/utils/internal/{jsonParse.test.ts → json-parse.test.ts} +1 -1
- package/src/core/utils/internal/observe-response-body-stream.test.ts +64 -0
- package/src/core/utils/internal/observe-response-body-stream.ts +76 -0
- package/src/core/utils/internal/{parseMultipartData.test.ts → parse-multipart-data.test.ts} +1 -1
- package/src/core/utils/internal/{parseMultipartData.ts → parse-multipart-data.ts} +1 -1
- package/src/core/utils/internal/{toReadonlyArray.test.ts → to-readonly-array.test.ts} +4 -4
- package/src/core/utils/logging/colors.ts +13 -0
- package/src/core/utils/logging/{getStatusCodeColor.test.ts → get-status-code-color.test.ts} +1 -1
- package/src/core/utils/logging/{getTimestamp.test.ts → get-timestamp.test.ts} +1 -1
- package/src/core/utils/logging/{serializeRequest.test.ts → serialize-request.test.ts} +1 -1
- package/src/core/utils/logging/{serializeResponse.test.ts → serialize-response.test.ts} +8 -10
- package/src/core/utils/logging/{serializeResponse.ts → serialize-response.ts} +2 -4
- package/src/core/utils/matching/match-request-url.test.ts +90 -0
- package/src/core/utils/matching/match-request-url.ts +45 -0
- package/src/core/utils/matching/{normalizePath.node.test.ts → normalize-path.node.test.ts} +2 -4
- package/src/core/utils/matching/{normalizePath.test.ts → normalize-path.test.ts} +2 -4
- package/src/core/utils/matching/{normalizePath.ts → normalize-path.ts} +8 -5
- package/src/core/utils/request/{getAllAcceptedMimeTypes.test.ts → get-all-accepted-mime-types.test.ts} +14 -14
- package/src/core/utils/request/get-request-cookies.ts +76 -0
- package/src/core/utils/request/store-response-cookies.ts +15 -0
- package/src/core/utils/request/{toPublicUrl.node.test.ts → to-public-url.node.test.ts} +1 -1
- package/src/core/utils/request/{toPublicUrl.test.ts → to-public-url.test.ts} +2 -2
- package/src/core/utils/{HttpResponse/decorators.ts → response-decorators.ts} +28 -9
- package/src/core/utils/url/{getAbsoluteUrl.node.test.ts → get-absolute-url.node.test.ts} +5 -7
- package/src/core/utils/url/{getAbsoluteUrl.test.ts → get-absolute-url.test.ts} +7 -7
- package/src/core/utils/url/{getAbsoluteUrl.ts → get-absolute-url.ts} +1 -1
- package/src/core/utils/url/is-absolute-url.test.ts +30 -0
- package/src/{core/handlers/GraphQLHandler.test.ts → graphql/graphql-handler.test.ts} +37 -36
- package/src/{core/handlers/GraphQLHandler.ts → graphql/graphql-handler.ts} +54 -41
- package/src/graphql/graphql-subscription-event.ts +39 -0
- package/src/graphql/graphql-subscription.test.ts +208 -0
- package/src/graphql/graphql-subscription.ts +1487 -0
- package/src/graphql/graphql.test.ts +14 -0
- package/src/graphql/graphql.ts +179 -0
- package/src/graphql/index.ts +34 -0
- package/src/{core/utils/internal/parseGraphQLRequest.test.ts → graphql/parse-graphql-request.test.ts} +47 -6
- package/src/{core/utils/internal/parseGraphQLRequest.ts → graphql/parse-graphql-request.ts} +59 -32
- package/src/{core/handlers/HttpHandler.test.ts → http/http-handler.test.ts} +107 -18
- package/src/{core/handlers/HttpHandler.ts → http/http-handler.ts} +16 -18
- package/src/{core/HttpResponse.test.ts → http/http-response.test.ts} +25 -27
- package/src/{core/HttpResponse.ts → http/http-response.ts} +15 -17
- package/src/{core → http}/http.ts +7 -7
- package/src/http/index.test.ts +19 -0
- package/src/http/index.ts +22 -0
- package/src/http/symbols.ts +19 -0
- package/src/iife/index.ts +2 -0
- package/src/mockServiceWorker.js +202 -91
- package/src/node/async-handlers-controller.test.ts +4 -4
- package/src/node/glossary.ts +8 -4
- package/src/node/index.ts +1 -6
- package/src/node/setup-server-common.ts +16 -73
- package/src/node/setup-server.ts +9 -40
- package/src/sse/index.test.ts +14 -0
- package/src/sse/index.ts +7 -0
- package/src/{core → sse}/sse.ts +105 -69
- package/src/tsconfig.core.build.json +5 -1
- package/src/tsconfig.core.json +8 -1
- package/src/tsconfig.node.json +1 -1
- package/src/tsconfig.src.json +1 -1
- package/src/{core → utils}/bypass.test.ts +22 -5
- package/src/{core → utils}/bypass.ts +11 -0
- package/src/{core → utils}/delay.ts +5 -5
- package/src/utils/get-clean-url-string.test.ts +24 -0
- package/src/utils/get-clean-url-string.ts +16 -0
- package/src/{core/getResponse.test.ts → utils/get-response.test.ts} +9 -9
- package/src/{core/getResponse.ts → utils/get-response.ts} +2 -2
- package/src/{core/isCommonAssetRequest.ts → utils/is-common-asset-request.ts} +4 -3
- package/src/utils/passthrough.test.ts +41 -0
- package/src/utils/passthrough.ts +46 -0
- package/src/vite/client.d.ts +16 -0
- package/src/vite/index.ts +4 -0
- package/src/vite/options.d.ts +5 -0
- package/src/vite/plugin.test.ts +918 -0
- package/src/vite/plugin.ts +133 -0
- package/src/vite/runtime.ts +117 -0
- package/src/vite/tsconfig.build.json +7 -0
- package/src/ws/index.ts +23 -0
- package/src/{core/ws/utils/attachWebSocketLogger.ts → ws/utils/attach-websocket-logger.ts} +45 -23
- package/src/{core/ws/utils/getMessageLength.test.ts → ws/utils/get-message-length.test.ts} +4 -4
- package/src/{core/ws/utils/getMessageLength.ts → ws/utils/get-message-length.ts} +1 -1
- package/src/{core/ws/utils/getPublicData.test.ts → ws/utils/get-public-data.test.ts} +7 -7
- package/src/ws/utils/get-public-data.ts +23 -0
- package/src/{core/ws/utils/truncateMessage.test.ts → ws/utils/truncate-message.test.ts} +3 -3
- package/src/{core/ws/WebSocketClientManager.test.ts → ws/websocket-client-manager.test.ts} +8 -9
- package/src/{core/ws/WebSocketClientManager.ts → ws/websocket-client-manager.ts} +24 -28
- package/src/{core/ws/WebSocketClientStore.ts → ws/websocket-client-store.ts} +2 -2
- package/src/{core/handlers/WebSocketHandler.test.ts → ws/websocket-handler.test.ts} +15 -15
- package/src/{core/handlers/WebSocketHandler.ts → ws/websocket-handler.ts} +144 -32
- package/src/{core/ws/WebSocketIndexedDBClientStore.ts → ws/websocket-indexeddb-client-store.ts} +12 -13
- package/src/{core/ws/WebSocketMemoryClientStore.ts → ws/websocket-memory-client-store.ts} +4 -4
- package/src/ws/websocket-upgrade.ts +83 -0
- package/src/{core → ws}/ws.test.ts +3 -4
- package/src/{core → ws}/ws.ts +106 -53
- package/browser/package.json +0 -31
- package/cli/package.json +0 -3
- package/config/package.json +0 -3
- package/config/scripts/postinstall.js +0 -36
- package/lib/browser/index.d.mts +0 -112
- package/lib/browser/index.mjs +0 -3706
- package/lib/browser/index.mjs.map +0 -1
- package/lib/core/HttpResponse-BTyqrRB6.d.mts +0 -371
- package/lib/core/HttpResponse-BXyXQFMJ.d.ts +0 -371
- package/lib/core/HttpResponse.d.mts +0 -6
- package/lib/core/HttpResponse.d.ts +0 -6
- package/lib/core/HttpResponse.js +0 -176
- package/lib/core/HttpResponse.js.map +0 -1
- package/lib/core/HttpResponse.mjs +0 -159
- package/lib/core/HttpResponse.mjs.map +0 -1
- package/lib/core/bypass.d.mts +0 -16
- package/lib/core/bypass.js +0 -42
- package/lib/core/bypass.js.map +0 -1
- package/lib/core/bypass.mjs +0 -22
- package/lib/core/bypass.mjs.map +0 -1
- package/lib/core/delay.d.mts +0 -18
- package/lib/core/delay.d.ts +0 -18
- package/lib/core/delay.js +0 -77
- package/lib/core/delay.js.map +0 -1
- package/lib/core/delay.mjs +0 -57
- package/lib/core/delay.mjs.map +0 -1
- package/lib/core/experimental/compat.d.mts +0 -17
- package/lib/core/experimental/compat.d.ts +0 -17
- package/lib/core/experimental/compat.js +0 -55
- package/lib/core/experimental/compat.js.map +0 -1
- package/lib/core/experimental/compat.mjs +0 -37
- package/lib/core/experimental/compat.mjs.map +0 -1
- package/lib/core/experimental/define-network.d.mts +0 -75
- package/lib/core/experimental/define-network.d.ts +0 -75
- package/lib/core/experimental/define-network.js +0 -134
- package/lib/core/experimental/define-network.js.map +0 -1
- package/lib/core/experimental/define-network.mjs +0 -119
- package/lib/core/experimental/define-network.mjs.map +0 -1
- package/lib/core/experimental/frames/http-frame.d.mts +0 -77
- package/lib/core/experimental/frames/http-frame.d.ts +0 -77
- package/lib/core/experimental/frames/http-frame.js +0 -197
- package/lib/core/experimental/frames/http-frame.js.map +0 -1
- package/lib/core/experimental/frames/http-frame.mjs +0 -181
- package/lib/core/experimental/frames/http-frame.mjs.map +0 -1
- package/lib/core/experimental/frames/network-frame.d.mts +0 -12
- package/lib/core/experimental/frames/network-frame.d.ts +0 -12
- package/lib/core/experimental/frames/network-frame.js +0 -35
- package/lib/core/experimental/frames/network-frame.js.map +0 -1
- package/lib/core/experimental/frames/network-frame.mjs +0 -15
- package/lib/core/experimental/frames/network-frame.mjs.map +0 -1
- package/lib/core/experimental/frames/websocket-frame.d.mts +0 -55
- package/lib/core/experimental/frames/websocket-frame.d.ts +0 -55
- package/lib/core/experimental/frames/websocket-frame.js +0 -131
- package/lib/core/experimental/frames/websocket-frame.js.map +0 -1
- package/lib/core/experimental/frames/websocket-frame.mjs +0 -118
- package/lib/core/experimental/frames/websocket-frame.mjs.map +0 -1
- package/lib/core/experimental/handlers-controller.d.mts +0 -36
- package/lib/core/experimental/handlers-controller.d.ts +0 -36
- package/lib/core/experimental/handlers-controller.js +0 -146
- package/lib/core/experimental/handlers-controller.js.map +0 -1
- package/lib/core/experimental/handlers-controller.mjs +0 -126
- package/lib/core/experimental/handlers-controller.mjs.map +0 -1
- package/lib/core/experimental/index.d.mts +0 -17
- package/lib/core/experimental/index.js.map +0 -1
- package/lib/core/experimental/index.mjs +0 -27
- package/lib/core/experimental/index.mjs.map +0 -1
- package/lib/core/experimental/on-unhandled-frame.d.mts +0 -12
- package/lib/core/experimental/on-unhandled-frame.d.ts +0 -12
- package/lib/core/experimental/on-unhandled-frame.js +0 -91
- package/lib/core/experimental/on-unhandled-frame.js.map +0 -1
- package/lib/core/experimental/on-unhandled-frame.mjs +0 -71
- package/lib/core/experimental/on-unhandled-frame.mjs.map +0 -1
- package/lib/core/experimental/request-utils.d.mts +0 -12
- package/lib/core/experimental/request-utils.d.ts +0 -12
- package/lib/core/experimental/request-utils.js +0 -50
- package/lib/core/experimental/request-utils.js.map +0 -1
- package/lib/core/experimental/request-utils.mjs +0 -30
- package/lib/core/experimental/request-utils.mjs.map +0 -1
- package/lib/core/experimental/setup-api.d.mts +0 -33
- package/lib/core/experimental/setup-api.d.ts +0 -33
- package/lib/core/experimental/setup-api.js +0 -58
- package/lib/core/experimental/setup-api.js.map +0 -1
- package/lib/core/experimental/setup-api.mjs +0 -40
- package/lib/core/experimental/setup-api.mjs.map +0 -1
- package/lib/core/experimental/sources/interceptor-source.d.mts +0 -28
- package/lib/core/experimental/sources/interceptor-source.d.ts +0 -28
- package/lib/core/experimental/sources/interceptor-source.js +0 -155
- package/lib/core/experimental/sources/interceptor-source.js.map +0 -1
- package/lib/core/experimental/sources/interceptor-source.mjs +0 -135
- package/lib/core/experimental/sources/interceptor-source.mjs.map +0 -1
- package/lib/core/experimental/sources/network-source.d.mts +0 -31
- package/lib/core/experimental/sources/network-source.d.ts +0 -31
- package/lib/core/experimental/sources/network-source.js +0 -51
- package/lib/core/experimental/sources/network-source.js.map +0 -1
- package/lib/core/experimental/sources/network-source.mjs +0 -32
- package/lib/core/experimental/sources/network-source.mjs.map +0 -1
- package/lib/core/getResponse.d.mts +0 -18
- package/lib/core/getResponse.d.ts +0 -18
- package/lib/core/getResponse.js +0 -35
- package/lib/core/getResponse.js.map +0 -1
- package/lib/core/getResponse.mjs +0 -17
- package/lib/core/getResponse.mjs.map +0 -1
- package/lib/core/graphql.d.mts +0 -76
- package/lib/core/graphql.d.ts +0 -76
- package/lib/core/graphql.js +0 -91
- package/lib/core/graphql.js.map +0 -1
- package/lib/core/graphql.mjs +0 -74
- package/lib/core/graphql.mjs.map +0 -1
- package/lib/core/handlers/GraphQLHandler.d.mts +0 -6
- package/lib/core/handlers/GraphQLHandler.d.ts +0 -6
- package/lib/core/handlers/GraphQLHandler.js +0 -232
- package/lib/core/handlers/GraphQLHandler.js.map +0 -1
- package/lib/core/handlers/GraphQLHandler.mjs +0 -221
- package/lib/core/handlers/GraphQLHandler.mjs.map +0 -1
- package/lib/core/handlers/HttpHandler.d.mts +0 -75
- package/lib/core/handlers/HttpHandler.d.ts +0 -75
- package/lib/core/handlers/HttpHandler.js +0 -129
- package/lib/core/handlers/HttpHandler.js.map +0 -1
- package/lib/core/handlers/HttpHandler.mjs +0 -113
- package/lib/core/handlers/HttpHandler.mjs.map +0 -1
- package/lib/core/handlers/RequestHandler.d.mts +0 -6
- package/lib/core/handlers/RequestHandler.d.ts +0 -6
- package/lib/core/handlers/RequestHandler.js +0 -300
- package/lib/core/handlers/RequestHandler.js.map +0 -1
- package/lib/core/handlers/RequestHandler.mjs +0 -283
- package/lib/core/handlers/RequestHandler.mjs.map +0 -1
- package/lib/core/handlers/WebSocketHandler.d.mts +0 -49
- package/lib/core/handlers/WebSocketHandler.d.ts +0 -49
- package/lib/core/handlers/WebSocketHandler.js +0 -178
- package/lib/core/handlers/WebSocketHandler.js.map +0 -1
- package/lib/core/handlers/WebSocketHandler.mjs +0 -160
- package/lib/core/handlers/WebSocketHandler.mjs.map +0 -1
- package/lib/core/http.d.mts +0 -31
- package/lib/core/http.js +0 -41
- package/lib/core/http.js.map +0 -1
- package/lib/core/http.mjs +0 -25
- package/lib/core/http.mjs.map +0 -1
- package/lib/core/index.d.mts +0 -27
- package/lib/core/index.js.map +0 -1
- package/lib/core/index.mjs +0 -52
- package/lib/core/index.mjs.map +0 -1
- package/lib/core/isCommonAssetRequest.d.mts +0 -20
- package/lib/core/isCommonAssetRequest.d.ts +0 -20
- package/lib/core/isCommonAssetRequest.js +0 -42
- package/lib/core/isCommonAssetRequest.js.map +0 -1
- package/lib/core/isCommonAssetRequest.mjs +0 -22
- package/lib/core/isCommonAssetRequest.mjs.map +0 -1
- package/lib/core/on-unhandled-frame-0KmwUmeV.d.ts +0 -56
- package/lib/core/on-unhandled-frame-gkokW4Rr.d.mts +0 -56
- package/lib/core/passthrough.d.mts +0 -24
- package/lib/core/passthrough.d.ts +0 -24
- package/lib/core/passthrough.js +0 -33
- package/lib/core/passthrough.js.map +0 -1
- package/lib/core/passthrough.mjs +0 -13
- package/lib/core/passthrough.mjs.map +0 -1
- package/lib/core/sharedOptions.d.mts +0 -68
- package/lib/core/sharedOptions.d.ts +0 -68
- package/lib/core/sharedOptions.js +0 -17
- package/lib/core/sharedOptions.js.map +0 -1
- package/lib/core/sharedOptions.mjs +0 -1
- package/lib/core/sharedOptions.mjs.map +0 -1
- package/lib/core/sse.d.mts +0 -102
- package/lib/core/sse.d.ts +0 -102
- package/lib/core/sse.js +0 -672
- package/lib/core/sse.js.map +0 -1
- package/lib/core/sse.mjs +0 -654
- package/lib/core/sse.mjs.map +0 -1
- package/lib/core/typeUtils.d.mts +0 -12
- package/lib/core/typeUtils.d.ts +0 -12
- package/lib/core/typeUtils.js +0 -17
- package/lib/core/typeUtils.js.map +0 -1
- package/lib/core/typeUtils.mjs +0 -1
- package/lib/core/typeUtils.mjs.map +0 -1
- package/lib/core/utils/HttpResponse/decorators.d.mts +0 -17
- package/lib/core/utils/HttpResponse/decorators.d.ts +0 -17
- package/lib/core/utils/HttpResponse/decorators.js +0 -71
- package/lib/core/utils/HttpResponse/decorators.js.map +0 -1
- package/lib/core/utils/HttpResponse/decorators.mjs +0 -41
- package/lib/core/utils/HttpResponse/decorators.mjs.map +0 -1
- package/lib/core/utils/cookieStore.d.mts +0 -13
- package/lib/core/utils/cookieStore.d.ts +0 -13
- package/lib/core/utils/cookieStore.js +0 -90
- package/lib/core/utils/cookieStore.js.map +0 -1
- package/lib/core/utils/cookieStore.mjs +0 -74
- package/lib/core/utils/cookieStore.mjs.map +0 -1
- package/lib/core/utils/executeHandlers.d.mts +0 -6
- package/lib/core/utils/executeHandlers.d.ts +0 -6
- package/lib/core/utils/executeHandlers.js +0 -51
- package/lib/core/utils/executeHandlers.js.map +0 -1
- package/lib/core/utils/executeHandlers.mjs +0 -31
- package/lib/core/utils/executeHandlers.mjs.map +0 -1
- package/lib/core/utils/handleRequest.d.mts +0 -30
- package/lib/core/utils/handleRequest.d.ts +0 -30
- package/lib/core/utils/handleRequest.js +0 -76
- package/lib/core/utils/handleRequest.js.map +0 -1
- package/lib/core/utils/handleRequest.mjs +0 -58
- package/lib/core/utils/handleRequest.mjs.map +0 -1
- package/lib/core/utils/internal/Disposable.d.mts +0 -7
- package/lib/core/utils/internal/Disposable.d.ts +0 -7
- package/lib/core/utils/internal/Disposable.js +0 -51
- package/lib/core/utils/internal/Disposable.js.map +0 -1
- package/lib/core/utils/internal/Disposable.mjs +0 -31
- package/lib/core/utils/internal/Disposable.mjs.map +0 -1
- package/lib/core/utils/internal/attachSiblingHandlers.d.mts +0 -15
- package/lib/core/utils/internal/attachSiblingHandlers.d.ts +0 -15
- package/lib/core/utils/internal/attachSiblingHandlers.js +0 -44
- package/lib/core/utils/internal/attachSiblingHandlers.js.map +0 -1
- package/lib/core/utils/internal/attachSiblingHandlers.mjs +0 -24
- package/lib/core/utils/internal/attachSiblingHandlers.mjs.map +0 -1
- package/lib/core/utils/internal/checkGlobals.d.mts +0 -3
- package/lib/core/utils/internal/checkGlobals.d.ts +0 -3
- package/lib/core/utils/internal/checkGlobals.js +0 -34
- package/lib/core/utils/internal/checkGlobals.js.map +0 -1
- package/lib/core/utils/internal/checkGlobals.mjs +0 -14
- package/lib/core/utils/internal/checkGlobals.mjs.map +0 -1
- package/lib/core/utils/internal/devUtils.d.mts +0 -28
- package/lib/core/utils/internal/devUtils.d.ts +0 -28
- package/lib/core/utils/internal/devUtils.js +0 -48
- package/lib/core/utils/internal/devUtils.js.map +0 -1
- package/lib/core/utils/internal/devUtils.mjs +0 -28
- package/lib/core/utils/internal/devUtils.mjs.map +0 -1
- package/lib/core/utils/internal/getCallFrame.d.mts +0 -6
- package/lib/core/utils/internal/getCallFrame.d.ts +0 -6
- package/lib/core/utils/internal/getCallFrame.js +0 -41
- package/lib/core/utils/internal/getCallFrame.js.map +0 -1
- package/lib/core/utils/internal/getCallFrame.mjs +0 -21
- package/lib/core/utils/internal/getCallFrame.mjs.map +0 -1
- package/lib/core/utils/internal/hasRefCounted.d.mts +0 -3
- package/lib/core/utils/internal/hasRefCounted.d.ts +0 -3
- package/lib/core/utils/internal/hasRefCounted.js +0 -34
- package/lib/core/utils/internal/hasRefCounted.js.map +0 -1
- package/lib/core/utils/internal/hasRefCounted.mjs +0 -14
- package/lib/core/utils/internal/hasRefCounted.mjs.map +0 -1
- package/lib/core/utils/internal/isHandlerKind.d.mts +0 -19
- package/lib/core/utils/internal/isHandlerKind.d.ts +0 -19
- package/lib/core/utils/internal/isHandlerKind.js +0 -30
- package/lib/core/utils/internal/isHandlerKind.js.map +0 -1
- package/lib/core/utils/internal/isHandlerKind.mjs +0 -10
- package/lib/core/utils/internal/isHandlerKind.mjs.map +0 -1
- package/lib/core/utils/internal/isIterable.d.mts +0 -20
- package/lib/core/utils/internal/isIterable.d.ts +0 -20
- package/lib/core/utils/internal/isIterable.js +0 -30
- package/lib/core/utils/internal/isIterable.js.map +0 -1
- package/lib/core/utils/internal/isIterable.mjs +0 -10
- package/lib/core/utils/internal/isIterable.mjs.map +0 -1
- package/lib/core/utils/internal/isObject.d.mts +0 -6
- package/lib/core/utils/internal/isObject.d.ts +0 -6
- package/lib/core/utils/internal/isObject.js +0 -27
- package/lib/core/utils/internal/isObject.js.map +0 -1
- package/lib/core/utils/internal/isObject.mjs +0 -7
- package/lib/core/utils/internal/isObject.mjs.map +0 -1
- package/lib/core/utils/internal/isStringEqual.d.mts +0 -6
- package/lib/core/utils/internal/isStringEqual.d.ts +0 -6
- package/lib/core/utils/internal/isStringEqual.js +0 -27
- package/lib/core/utils/internal/isStringEqual.js.map +0 -1
- package/lib/core/utils/internal/isStringEqual.mjs +0 -7
- package/lib/core/utils/internal/isStringEqual.mjs.map +0 -1
- package/lib/core/utils/internal/jsonParse.d.mts +0 -7
- package/lib/core/utils/internal/jsonParse.d.ts +0 -7
- package/lib/core/utils/internal/jsonParse.js +0 -31
- package/lib/core/utils/internal/jsonParse.js.map +0 -1
- package/lib/core/utils/internal/jsonParse.mjs +0 -11
- package/lib/core/utils/internal/jsonParse.mjs.map +0 -1
- package/lib/core/utils/internal/mergeRight.d.mts +0 -7
- package/lib/core/utils/internal/mergeRight.d.ts +0 -7
- package/lib/core/utils/internal/mergeRight.js +0 -43
- package/lib/core/utils/internal/mergeRight.js.map +0 -1
- package/lib/core/utils/internal/mergeRight.mjs +0 -23
- package/lib/core/utils/internal/mergeRight.mjs.map +0 -1
- package/lib/core/utils/internal/parseGraphQLRequest.d.mts +0 -6
- package/lib/core/utils/internal/parseGraphQLRequest.d.ts +0 -6
- package/lib/core/utils/internal/parseGraphQLRequest.js +0 -146
- package/lib/core/utils/internal/parseGraphQLRequest.js.map +0 -1
- package/lib/core/utils/internal/parseGraphQLRequest.mjs +0 -129
- package/lib/core/utils/internal/parseGraphQLRequest.mjs.map +0 -1
- package/lib/core/utils/internal/parseMultipartData.d.mts +0 -14
- package/lib/core/utils/internal/parseMultipartData.d.ts +0 -14
- package/lib/core/utils/internal/parseMultipartData.js +0 -84
- package/lib/core/utils/internal/parseMultipartData.js.map +0 -1
- package/lib/core/utils/internal/parseMultipartData.mjs +0 -64
- package/lib/core/utils/internal/parseMultipartData.mjs.map +0 -1
- package/lib/core/utils/internal/pipeEvents.d.mts +0 -8
- package/lib/core/utils/internal/pipeEvents.d.ts +0 -8
- package/lib/core/utils/internal/pipeEvents.js +0 -37
- package/lib/core/utils/internal/pipeEvents.js.map +0 -1
- package/lib/core/utils/internal/pipeEvents.mjs +0 -17
- package/lib/core/utils/internal/pipeEvents.mjs.map +0 -1
- package/lib/core/utils/internal/toReadonlyArray.d.mts +0 -6
- package/lib/core/utils/internal/toReadonlyArray.d.ts +0 -6
- package/lib/core/utils/internal/toReadonlyArray.js +0 -29
- package/lib/core/utils/internal/toReadonlyArray.js.map +0 -1
- package/lib/core/utils/internal/toReadonlyArray.mjs +0 -9
- package/lib/core/utils/internal/toReadonlyArray.mjs.map +0 -1
- package/lib/core/utils/internal/tryCatch.d.mts +0 -3
- package/lib/core/utils/internal/tryCatch.d.ts +0 -3
- package/lib/core/utils/internal/tryCatch.js +0 -32
- package/lib/core/utils/internal/tryCatch.js.map +0 -1
- package/lib/core/utils/internal/tryCatch.mjs +0 -12
- package/lib/core/utils/internal/tryCatch.mjs.map +0 -1
- package/lib/core/utils/logging/getStatusCodeColor.d.mts +0 -11
- package/lib/core/utils/logging/getStatusCodeColor.d.ts +0 -11
- package/lib/core/utils/logging/getStatusCodeColor.js +0 -40
- package/lib/core/utils/logging/getStatusCodeColor.js.map +0 -1
- package/lib/core/utils/logging/getStatusCodeColor.mjs +0 -20
- package/lib/core/utils/logging/getStatusCodeColor.mjs.map +0 -1
- package/lib/core/utils/logging/getTimestamp.d.mts +0 -9
- package/lib/core/utils/logging/getTimestamp.d.ts +0 -9
- package/lib/core/utils/logging/getTimestamp.js +0 -32
- package/lib/core/utils/logging/getTimestamp.js.map +0 -1
- package/lib/core/utils/logging/getTimestamp.mjs +0 -12
- package/lib/core/utils/logging/getTimestamp.mjs.map +0 -1
- package/lib/core/utils/logging/serializeRequest.d.mts +0 -12
- package/lib/core/utils/logging/serializeRequest.d.ts +0 -12
- package/lib/core/utils/logging/serializeRequest.js +0 -34
- package/lib/core/utils/logging/serializeRequest.js.map +0 -1
- package/lib/core/utils/logging/serializeRequest.mjs +0 -14
- package/lib/core/utils/logging/serializeRequest.mjs.map +0 -1
- package/lib/core/utils/logging/serializeResponse.d.mts +0 -9
- package/lib/core/utils/logging/serializeResponse.d.ts +0 -9
- package/lib/core/utils/logging/serializeResponse.js +0 -48
- package/lib/core/utils/logging/serializeResponse.js.map +0 -1
- package/lib/core/utils/logging/serializeResponse.mjs +0 -18
- package/lib/core/utils/logging/serializeResponse.mjs.map +0 -1
- package/lib/core/utils/matching/matchRequestUrl.d.mts +0 -20
- package/lib/core/utils/matching/matchRequestUrl.d.ts +0 -20
- package/lib/core/utils/matching/matchRequestUrl.js +0 -55
- package/lib/core/utils/matching/matchRequestUrl.js.map +0 -1
- package/lib/core/utils/matching/matchRequestUrl.mjs +0 -35
- package/lib/core/utils/matching/matchRequestUrl.mjs.map +0 -1
- package/lib/core/utils/matching/normalizePath.d.mts +0 -13
- package/lib/core/utils/matching/normalizePath.d.ts +0 -13
- package/lib/core/utils/matching/normalizePath.js +0 -33
- package/lib/core/utils/matching/normalizePath.js.map +0 -1
- package/lib/core/utils/matching/normalizePath.mjs +0 -13
- package/lib/core/utils/matching/normalizePath.mjs.map +0 -1
- package/lib/core/utils/request/getAllAcceptedMimeTypes.d.mts +0 -14
- package/lib/core/utils/request/getAllAcceptedMimeTypes.d.ts +0 -14
- package/lib/core/utils/request/getAllAcceptedMimeTypes.js +0 -61
- package/lib/core/utils/request/getAllAcceptedMimeTypes.js.map +0 -1
- package/lib/core/utils/request/getAllAcceptedMimeTypes.mjs +0 -41
- package/lib/core/utils/request/getAllAcceptedMimeTypes.mjs.map +0 -1
- package/lib/core/utils/request/getRequestCookies.d.mts +0 -3
- package/lib/core/utils/request/getRequestCookies.d.ts +0 -3
- package/lib/core/utils/request/getRequestCookies.js +0 -79
- package/lib/core/utils/request/getRequestCookies.js.map +0 -1
- package/lib/core/utils/request/getRequestCookies.mjs +0 -62
- package/lib/core/utils/request/getRequestCookies.mjs.map +0 -1
- package/lib/core/utils/request/onUnhandledRequest.d.mts +0 -9
- package/lib/core/utils/request/onUnhandledRequest.d.ts +0 -9
- package/lib/core/utils/request/onUnhandledRequest.js +0 -76
- package/lib/core/utils/request/onUnhandledRequest.js.map +0 -1
- package/lib/core/utils/request/onUnhandledRequest.mjs +0 -56
- package/lib/core/utils/request/onUnhandledRequest.mjs.map +0 -1
- package/lib/core/utils/request/storeResponseCookies.d.mts +0 -3
- package/lib/core/utils/request/storeResponseCookies.d.ts +0 -3
- package/lib/core/utils/request/storeResponseCookies.js +0 -32
- package/lib/core/utils/request/storeResponseCookies.js.map +0 -1
- package/lib/core/utils/request/storeResponseCookies.mjs +0 -12
- package/lib/core/utils/request/storeResponseCookies.mjs.map +0 -1
- package/lib/core/utils/request/toPublicUrl.d.mts +0 -7
- package/lib/core/utils/request/toPublicUrl.d.ts +0 -7
- package/lib/core/utils/request/toPublicUrl.js +0 -31
- package/lib/core/utils/request/toPublicUrl.js.map +0 -1
- package/lib/core/utils/request/toPublicUrl.mjs +0 -11
- package/lib/core/utils/request/toPublicUrl.mjs.map +0 -1
- package/lib/core/utils/toResponseInit.d.mts +0 -3
- package/lib/core/utils/toResponseInit.d.ts +0 -3
- package/lib/core/utils/toResponseInit.js +0 -31
- package/lib/core/utils/toResponseInit.js.map +0 -1
- package/lib/core/utils/toResponseInit.mjs +0 -11
- package/lib/core/utils/toResponseInit.mjs.map +0 -1
- package/lib/core/utils/url/cleanUrl.d.mts +0 -7
- package/lib/core/utils/url/cleanUrl.d.ts +0 -7
- package/lib/core/utils/url/cleanUrl.js +0 -31
- package/lib/core/utils/url/cleanUrl.js.map +0 -1
- package/lib/core/utils/url/cleanUrl.mjs +0 -11
- package/lib/core/utils/url/cleanUrl.mjs.map +0 -1
- package/lib/core/utils/url/getAbsoluteUrl.d.mts +0 -6
- package/lib/core/utils/url/getAbsoluteUrl.d.ts +0 -6
- package/lib/core/utils/url/getAbsoluteUrl.js +0 -38
- package/lib/core/utils/url/getAbsoluteUrl.js.map +0 -1
- package/lib/core/utils/url/getAbsoluteUrl.mjs +0 -18
- package/lib/core/utils/url/getAbsoluteUrl.mjs.map +0 -1
- package/lib/core/utils/url/isAbsoluteUrl.d.mts +0 -6
- package/lib/core/utils/url/isAbsoluteUrl.d.ts +0 -6
- package/lib/core/utils/url/isAbsoluteUrl.js +0 -27
- package/lib/core/utils/url/isAbsoluteUrl.js.map +0 -1
- package/lib/core/utils/url/isAbsoluteUrl.mjs +0 -7
- package/lib/core/utils/url/isAbsoluteUrl.mjs.map +0 -1
- package/lib/core/ws/WebSocketClientManager.d.mts +0 -65
- package/lib/core/ws/WebSocketClientManager.d.ts +0 -65
- package/lib/core/ws/WebSocketClientManager.js +0 -163
- package/lib/core/ws/WebSocketClientManager.js.map +0 -1
- package/lib/core/ws/WebSocketClientManager.mjs +0 -143
- package/lib/core/ws/WebSocketClientManager.mjs.map +0 -1
- package/lib/core/ws/WebSocketClientStore.d.mts +0 -13
- package/lib/core/ws/WebSocketClientStore.d.ts +0 -13
- package/lib/core/ws/WebSocketClientStore.js +0 -26
- package/lib/core/ws/WebSocketClientStore.js.map +0 -1
- package/lib/core/ws/WebSocketClientStore.mjs +0 -6
- package/lib/core/ws/WebSocketClientStore.mjs.map +0 -1
- package/lib/core/ws/WebSocketIndexedDBClientStore.d.mts +0 -14
- package/lib/core/ws/WebSocketIndexedDBClientStore.d.ts +0 -14
- package/lib/core/ws/WebSocketIndexedDBClientStore.js +0 -131
- package/lib/core/ws/WebSocketIndexedDBClientStore.js.map +0 -1
- package/lib/core/ws/WebSocketIndexedDBClientStore.mjs +0 -111
- package/lib/core/ws/WebSocketIndexedDBClientStore.mjs.map +0 -1
- package/lib/core/ws/WebSocketMemoryClientStore.d.mts +0 -12
- package/lib/core/ws/WebSocketMemoryClientStore.d.ts +0 -12
- package/lib/core/ws/WebSocketMemoryClientStore.js +0 -42
- package/lib/core/ws/WebSocketMemoryClientStore.js.map +0 -1
- package/lib/core/ws/WebSocketMemoryClientStore.mjs +0 -22
- package/lib/core/ws/WebSocketMemoryClientStore.mjs.map +0 -1
- package/lib/core/ws/handleWebSocketEvent.d.mts +0 -20
- package/lib/core/ws/handleWebSocketEvent.d.ts +0 -20
- package/lib/core/ws/handleWebSocketEvent.js +0 -61
- package/lib/core/ws/handleWebSocketEvent.js.map +0 -1
- package/lib/core/ws/handleWebSocketEvent.mjs +0 -43
- package/lib/core/ws/handleWebSocketEvent.mjs.map +0 -1
- package/lib/core/ws/utils/attachWebSocketLogger.d.mts +0 -18
- package/lib/core/ws/utils/attachWebSocketLogger.d.ts +0 -18
- package/lib/core/ws/utils/attachWebSocketLogger.js +0 -228
- package/lib/core/ws/utils/attachWebSocketLogger.js.map +0 -1
- package/lib/core/ws/utils/attachWebSocketLogger.mjs +0 -208
- package/lib/core/ws/utils/attachWebSocketLogger.mjs.map +0 -1
- package/lib/core/ws/utils/getMessageLength.d.mts +0 -11
- package/lib/core/ws/utils/getMessageLength.d.ts +0 -11
- package/lib/core/ws/utils/getMessageLength.js +0 -34
- package/lib/core/ws/utils/getMessageLength.js.map +0 -1
- package/lib/core/ws/utils/getMessageLength.mjs +0 -14
- package/lib/core/ws/utils/getMessageLength.mjs.map +0 -1
- package/lib/core/ws/utils/getPublicData.d.mts +0 -5
- package/lib/core/ws/utils/getPublicData.d.ts +0 -5
- package/lib/core/ws/utils/getPublicData.js +0 -37
- package/lib/core/ws/utils/getPublicData.js.map +0 -1
- package/lib/core/ws/utils/getPublicData.mjs +0 -17
- package/lib/core/ws/utils/getPublicData.mjs.map +0 -1
- package/lib/core/ws/utils/truncateMessage.d.mts +0 -3
- package/lib/core/ws/utils/truncateMessage.d.ts +0 -3
- package/lib/core/ws/utils/truncateMessage.js +0 -31
- package/lib/core/ws/utils/truncateMessage.js.map +0 -1
- package/lib/core/ws/utils/truncateMessage.mjs +0 -11
- package/lib/core/ws/utils/truncateMessage.mjs.map +0 -1
- package/lib/core/ws/webSocketInterceptor.d.mts +0 -5
- package/lib/core/ws/webSocketInterceptor.d.ts +0 -5
- package/lib/core/ws/webSocketInterceptor.js +0 -26
- package/lib/core/ws/webSocketInterceptor.js.map +0 -1
- package/lib/core/ws/webSocketInterceptor.mjs +0 -6
- package/lib/core/ws/webSocketInterceptor.mjs.map +0 -1
- package/lib/core/ws.d.mts +0 -88
- package/lib/core/ws.d.ts +0 -88
- package/lib/core/ws.js +0 -94
- package/lib/core/ws.js.map +0 -1
- package/lib/core/ws.mjs +0 -80
- package/lib/core/ws.mjs.map +0 -1
- package/lib/native/index.d.mts +0 -66
- package/lib/native/index.d.ts +0 -66
- package/lib/native/index.js +0 -88
- package/lib/native/index.js.map +0 -1
- package/lib/native/index.mjs +0 -67
- package/lib/native/index.mjs.map +0 -1
- package/lib/node/index.d.mts +0 -113
- package/lib/node/index.mjs +0 -185
- package/lib/node/index.mjs.map +0 -1
- package/lib/shims/cookie.d.mts +0 -7
- package/lib/shims/cookie.d.ts +0 -7
- package/lib/shims/cookie.js +0 -294
- package/lib/shims/cookie.mjs +0 -286
- package/lib/shims/statuses.d.mts +0 -6
- package/lib/shims/statuses.d.ts +0 -6
- package/lib/shims/statuses.js +0 -195
- package/lib/shims/statuses.mjs +0 -187
- package/native/package.json +0 -30
- package/node/package.json +0 -33
- package/src/browser/utils/pruneGetRequestBody.test.ts +0 -51
- package/src/browser/utils/pruneGetRequestBody.ts +0 -21
- package/src/core/experimental/compat.ts +0 -50
- package/src/core/experimental/setup-api.ts +0 -55
- package/src/core/graphql.test.ts +0 -11
- package/src/core/graphql.ts +0 -136
- package/src/core/passthrough.test.ts +0 -11
- package/src/core/passthrough.ts +0 -25
- package/src/core/sharedOptions.ts +0 -71
- package/src/core/typeUtils.ts +0 -26
- package/src/core/utils/handleRequest.test.ts +0 -574
- package/src/core/utils/handleRequest.ts +0 -117
- package/src/core/utils/internal/checkGlobals.ts +0 -17
- package/src/core/utils/internal/isHandlerKind.test.ts +0 -62
- package/src/core/utils/internal/isHandlerKind.ts +0 -17
- package/src/core/utils/internal/isIterable.ts +0 -32
- package/src/core/utils/internal/mergeRight.test.ts +0 -43
- package/src/core/utils/internal/mergeRight.ts +0 -30
- package/src/core/utils/internal/pipeEvents.test.ts +0 -14
- package/src/core/utils/internal/pipeEvents.ts +0 -26
- package/src/core/utils/internal/tryCatch.test.ts +0 -29
- package/src/core/utils/internal/tryCatch.ts +0 -11
- package/src/core/utils/matching/matchRequestUrl.test.ts +0 -267
- package/src/core/utils/matching/matchRequestUrl.ts +0 -77
- package/src/core/utils/request/getRequestCookies.ts +0 -88
- package/src/core/utils/request/onUnhandledRequest.node.test.ts +0 -62
- package/src/core/utils/request/onUnhandledRequest.test.ts +0 -226
- package/src/core/utils/request/onUnhandledRequest.ts +0 -81
- package/src/core/utils/request/storeResponseCookies.ts +0 -15
- package/src/core/utils/url/cleanUrl.test.ts +0 -22
- package/src/core/utils/url/cleanUrl.ts +0 -16
- package/src/core/utils/url/isAbsoluteUrl.test.ts +0 -32
- package/src/core/ws/handleWebSocketEvent.ts +0 -68
- package/src/core/ws/utils/getPublicData.ts +0 -18
- package/src/core/ws/webSocketInterceptor.ts +0 -3
- package/src/native/index.ts +0 -44
- package/src/package.json +0 -3
- package/src/shims/cookie.ts +0 -7
- package/src/shims/statuses.ts +0 -6
- /package/src/browser/utils/{getAbsoluteWorkerUrl.ts → get-absolute-worker-url.ts} +0 -0
- /package/src/core/utils/internal/{devUtils.ts → dev-utils.ts} +0 -0
- /package/src/core/utils/internal/{isObject.ts → is-object.ts} +0 -0
- /package/src/core/utils/internal/{isStringEqual.ts → is-string-equal.ts} +0 -0
- /package/src/core/utils/internal/{jsonParse.ts → json-parse.ts} +0 -0
- /package/src/core/utils/internal/{toReadonlyArray.ts → to-readonly-array.ts} +0 -0
- /package/src/core/utils/logging/{getStatusCodeColor.ts → get-status-code-color.ts} +0 -0
- /package/src/core/utils/logging/{getTimestamp.ts → get-timestamp.ts} +0 -0
- /package/src/core/utils/logging/{serializeRequest.ts → serialize-request.ts} +0 -0
- /package/src/core/utils/request/{getAllAcceptedMimeTypes.ts → get-all-accepted-mime-types.ts} +0 -0
- /package/src/core/utils/request/{toPublicUrl.ts → to-public-url.ts} +0 -0
- /package/src/core/utils/{toResponseInit.ts → to-response-init.ts} +0 -0
- /package/src/core/utils/url/{isAbsoluteUrl.ts → is-absolute-url.ts} +0 -0
- /package/src/{core → http}/http.test.ts +0 -0
- /package/src/{core/ws/utils/truncateMessage.ts → ws/utils/truncate-message.ts} +0 -0
|
@@ -0,0 +1,1487 @@
|
|
|
1
|
+
import { invariant } from 'outvariant'
|
|
2
|
+
import { Emitter, TypedEvent } from 'rettime'
|
|
3
|
+
import { parse, OperationTypeNode, type GraphQLError } from 'graphql'
|
|
4
|
+
import { resolveWebSocketUrl } from '@mswjs/interceptors'
|
|
5
|
+
import type {
|
|
6
|
+
WebSocketClientHandle,
|
|
7
|
+
WebSocketConnectionEventData,
|
|
8
|
+
WebSocketData,
|
|
9
|
+
WebSocketServerHandle,
|
|
10
|
+
} from '@mswjs/interceptors/WebSocket'
|
|
11
|
+
import { http } from '#http/http'
|
|
12
|
+
import { webSocketUpgrade } from '#ws/websocket-upgrade'
|
|
13
|
+
import {
|
|
14
|
+
WebSocketHandler,
|
|
15
|
+
kConnect,
|
|
16
|
+
type WebSocketHandlerConnection,
|
|
17
|
+
type WebSocketResolutionContext,
|
|
18
|
+
} from '#ws/websocket-handler'
|
|
19
|
+
import { GraphQLSubscriptionEvent } from './graphql-subscription-event'
|
|
20
|
+
import {
|
|
21
|
+
matchRequestUrl,
|
|
22
|
+
type Path,
|
|
23
|
+
type PathParams,
|
|
24
|
+
} from '#core/utils/matching/match-request-url'
|
|
25
|
+
import type { ResponseResolverFinalizeFunction } from '#core/handlers/request-handler'
|
|
26
|
+
import type { MaybePromise } from '#core/type-utils'
|
|
27
|
+
import { attachSiblingHandlers } from '#core/utils/internal/attach-sibling-handlers'
|
|
28
|
+
import { jsonParse } from '#core/utils/internal/json-parse'
|
|
29
|
+
import { devUtils } from '#core/utils/internal/dev-utils'
|
|
30
|
+
import { getTimestamp } from '#core/utils/logging/get-timestamp'
|
|
31
|
+
import { toPublicUrl } from '#core/utils/request/to-public-url'
|
|
32
|
+
import { colors } from '#core/utils/logging/colors'
|
|
33
|
+
import {
|
|
34
|
+
GraphQLHandler,
|
|
35
|
+
isDocumentNode,
|
|
36
|
+
type DocumentTypeDecoration,
|
|
37
|
+
type GraphQLHandlerInfo,
|
|
38
|
+
type GraphQLHandlerNameSelector,
|
|
39
|
+
type GraphQLQuery,
|
|
40
|
+
type GraphQLVariables,
|
|
41
|
+
} from './graphql-handler'
|
|
42
|
+
import {
|
|
43
|
+
parseDocumentNode,
|
|
44
|
+
type ParsedGraphQLQuery,
|
|
45
|
+
} from './parse-graphql-request'
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Messages of the `graphql-transport-ws` protocol.
|
|
49
|
+
* @see https://github.com/graphql/graphql-over-http/blob/main/rfcs/GraphQLOverWebSocket.md
|
|
50
|
+
*/
|
|
51
|
+
interface GraphQLWebSocketInitMessage {
|
|
52
|
+
type: 'connection_init'
|
|
53
|
+
payload?: Record<string, unknown>
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface GraphQLWebSocketSubscribePayload<
|
|
57
|
+
Variables extends GraphQLVariables = GraphQLVariables,
|
|
58
|
+
> {
|
|
59
|
+
operationName?: string | null
|
|
60
|
+
query: string
|
|
61
|
+
variables?: Variables
|
|
62
|
+
extensions?: Record<string, unknown>
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface GraphQLWebSocketSubscribeMessage<
|
|
66
|
+
Variables extends GraphQLVariables = GraphQLVariables,
|
|
67
|
+
> {
|
|
68
|
+
type: 'subscribe'
|
|
69
|
+
id: string
|
|
70
|
+
payload: GraphQLWebSocketSubscribePayload<Variables>
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface GraphQLWebSocketCompleteMessage {
|
|
74
|
+
type: 'complete'
|
|
75
|
+
id: string
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface GraphQLWebSocketPingMessage {
|
|
79
|
+
type: 'ping'
|
|
80
|
+
payload?: Record<string, unknown>
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface GraphQLWebSocketPongMessage {
|
|
84
|
+
type: 'pong'
|
|
85
|
+
payload?: Record<string, unknown>
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
type GraphQLWebSocketClientMessage =
|
|
89
|
+
| GraphQLWebSocketInitMessage
|
|
90
|
+
| GraphQLWebSocketSubscribeMessage
|
|
91
|
+
| GraphQLWebSocketCompleteMessage
|
|
92
|
+
| GraphQLWebSocketPingMessage
|
|
93
|
+
| GraphQLWebSocketPongMessage
|
|
94
|
+
|
|
95
|
+
interface GraphQLWebSocketAcknowledgeMessage {
|
|
96
|
+
type: 'connection_ack'
|
|
97
|
+
payload?: Record<string, unknown>
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface GraphQLWebSocketNextMessage {
|
|
101
|
+
type: 'next'
|
|
102
|
+
id: string
|
|
103
|
+
payload: GraphQLSubscriptionPayload
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface GraphQLWebSocketErrorMessage {
|
|
107
|
+
type: 'error'
|
|
108
|
+
id: string
|
|
109
|
+
payload: ReadonlyArray<Partial<GraphQLError>>
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
type GraphQLWebSocketServerMessage =
|
|
113
|
+
| GraphQLWebSocketAcknowledgeMessage
|
|
114
|
+
| GraphQLWebSocketNextMessage
|
|
115
|
+
| GraphQLWebSocketErrorMessage
|
|
116
|
+
| GraphQLWebSocketCompleteMessage
|
|
117
|
+
| GraphQLWebSocketPingMessage
|
|
118
|
+
| GraphQLWebSocketPongMessage
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* A GraphQL execution result published to a subscription.
|
|
122
|
+
*/
|
|
123
|
+
export interface GraphQLSubscriptionPayload<
|
|
124
|
+
Query extends GraphQLQuery = GraphQLQuery,
|
|
125
|
+
> {
|
|
126
|
+
data?: Query | null
|
|
127
|
+
errors?: ReadonlyArray<Partial<GraphQLError>> | null
|
|
128
|
+
extensions?: Record<string, unknown>
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function createInitMessage(payload?: Record<string, unknown>): string {
|
|
132
|
+
return JSON.stringify({
|
|
133
|
+
type: 'connection_init',
|
|
134
|
+
payload,
|
|
135
|
+
} satisfies GraphQLWebSocketInitMessage)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function createAcknowledgeMessage(): string {
|
|
139
|
+
return JSON.stringify({
|
|
140
|
+
type: 'connection_ack',
|
|
141
|
+
} satisfies GraphQLWebSocketAcknowledgeMessage)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function createNextMessage(args: {
|
|
145
|
+
id: string
|
|
146
|
+
payload: GraphQLSubscriptionPayload
|
|
147
|
+
}): string {
|
|
148
|
+
return JSON.stringify({
|
|
149
|
+
id: args.id,
|
|
150
|
+
type: 'next',
|
|
151
|
+
payload: args.payload,
|
|
152
|
+
} satisfies GraphQLWebSocketNextMessage)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function createErrorMessage(args: {
|
|
156
|
+
id: string
|
|
157
|
+
payload: ReadonlyArray<Partial<GraphQLError>>
|
|
158
|
+
}): string {
|
|
159
|
+
return JSON.stringify({
|
|
160
|
+
id: args.id,
|
|
161
|
+
type: 'error',
|
|
162
|
+
payload: args.payload,
|
|
163
|
+
} satisfies GraphQLWebSocketErrorMessage)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function createCompleteMessage(args: { id: string }): string {
|
|
167
|
+
return JSON.stringify({
|
|
168
|
+
id: args.id,
|
|
169
|
+
type: 'complete',
|
|
170
|
+
} satisfies GraphQLWebSocketCompleteMessage)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function createPongMessage(): string {
|
|
174
|
+
return JSON.stringify({
|
|
175
|
+
type: 'pong',
|
|
176
|
+
} satisfies GraphQLWebSocketPongMessage)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Construct a request representing the WebSocket upgrade of the given
|
|
181
|
+
* connection. GraphQL subscriptions have no request of their own, so
|
|
182
|
+
* this describes the connection they are multiplexed over.
|
|
183
|
+
*/
|
|
184
|
+
function createUpgradeRequest(url: URL): Request {
|
|
185
|
+
return new Request(url, {
|
|
186
|
+
headers: {
|
|
187
|
+
connection: 'upgrade',
|
|
188
|
+
upgrade: 'websocket',
|
|
189
|
+
},
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function parseGraphQLWebSocketMessage<MessageType extends { type: string }>(
|
|
194
|
+
data: WebSocketData,
|
|
195
|
+
): MessageType | undefined {
|
|
196
|
+
if (typeof data !== 'string') {
|
|
197
|
+
return undefined
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const message = jsonParse<MessageType>(data)
|
|
201
|
+
|
|
202
|
+
if (!message || typeof message.type !== 'string') {
|
|
203
|
+
return undefined
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return message
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* A subscriber provided by a `GraphQLSubscriptionHandler` for a particular
|
|
211
|
+
* WebSocket connection. Returns true if the handler matched the parsed
|
|
212
|
+
* subscribe operation and resolved it.
|
|
213
|
+
*/
|
|
214
|
+
type GraphQLSubscriptionSubscriber = (args: {
|
|
215
|
+
node: ParsedGraphQLQuery
|
|
216
|
+
message: GraphQLWebSocketSubscribeMessage
|
|
217
|
+
}) => boolean
|
|
218
|
+
|
|
219
|
+
interface GraphQLSubscriptionSubscriberEntry {
|
|
220
|
+
transport: GraphQLSubscriptionTransportHandler
|
|
221
|
+
subscriber: GraphQLSubscriptionSubscriber
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
type GraphQLSubscriptionCleanup = () => MaybePromise<void>
|
|
225
|
+
|
|
226
|
+
interface GraphQLSubscriptionConnection {
|
|
227
|
+
client: WebSocketClientHandle
|
|
228
|
+
server: WebSocketServerHandle
|
|
229
|
+
subscribers: Map<WebSocketHandler, GraphQLSubscriptionSubscriberEntry>
|
|
230
|
+
/**
|
|
231
|
+
* The active subscriptions of this connection, mapped to the cleanups
|
|
232
|
+
* scheduled for them via the resolver's `finalize()`.
|
|
233
|
+
*/
|
|
234
|
+
subscriptions: Map<string, Array<GraphQLSubscriptionCleanup>>
|
|
235
|
+
events?: WebSocketResolutionContext['events']
|
|
236
|
+
/**
|
|
237
|
+
* The payload of the client's `connection_init` message (i.e. the
|
|
238
|
+
* `connectionParams` of the GraphQL client). Kept so it can be
|
|
239
|
+
* replayed to the original server on passthrough.
|
|
240
|
+
*/
|
|
241
|
+
connectionParams?: Record<string, unknown>
|
|
242
|
+
/**
|
|
243
|
+
* Resolves once the original server has acknowledged this connection.
|
|
244
|
+
* The upstream session is established once per connection, no matter
|
|
245
|
+
* how many subscriptions pass through it.
|
|
246
|
+
*/
|
|
247
|
+
upstreamSession?: Promise<void>
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Connect to the original server and initialize the `graphql-transport-ws`
|
|
252
|
+
* session for the given connection, at most once.
|
|
253
|
+
*
|
|
254
|
+
* @note The server connection is shared by every subscription of this
|
|
255
|
+
* client. Initializing it more than once makes a compliant GraphQL server
|
|
256
|
+
* close it ("Too many initialisation requests").
|
|
257
|
+
*/
|
|
258
|
+
function ensureUpstreamSession(
|
|
259
|
+
connection: GraphQLSubscriptionConnection,
|
|
260
|
+
): Promise<void> {
|
|
261
|
+
if (connection.upstreamSession) {
|
|
262
|
+
return connection.upstreamSession
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const { server } = connection
|
|
266
|
+
|
|
267
|
+
connection.upstreamSession = new Promise<void>((resolve) => {
|
|
268
|
+
server.addEventListener('message', (event) => {
|
|
269
|
+
const message =
|
|
270
|
+
parseGraphQLWebSocketMessage<GraphQLWebSocketServerMessage>(event.data)
|
|
271
|
+
|
|
272
|
+
if (message?.type === 'connection_ack') {
|
|
273
|
+
// Prevent the original acknowledgement from being forwarded to
|
|
274
|
+
// the client: it has already received a mocked one on connect.
|
|
275
|
+
event.preventDefault()
|
|
276
|
+
resolve()
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
server.addEventListener(
|
|
281
|
+
'open',
|
|
282
|
+
() => {
|
|
283
|
+
server.send(createInitMessage(connection.connectionParams))
|
|
284
|
+
},
|
|
285
|
+
{ once: true },
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
server.connect()
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
return connection.upstreamSession
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* The `graphql-transport-ws` sessions of the intercepted WebSocket
|
|
296
|
+
* connections, keyed by the client id.
|
|
297
|
+
*
|
|
298
|
+
* @note This registry is module-level, and not per-transport, on purpose.
|
|
299
|
+
* Multiple `graphql.link()` calls to the same endpoint create multiple
|
|
300
|
+
* transports, and all of them must share a single session per connection.
|
|
301
|
+
* Otherwise, each transport binds its own protocol listeners to the same
|
|
302
|
+
* client, which makes it receive duplicate `connection_ack`/`pong` frames
|
|
303
|
+
* and resolves matching subscription handlers more than once.
|
|
304
|
+
*/
|
|
305
|
+
const connections = new Map<string, GraphQLSubscriptionConnection>()
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* The WebSocket protocol implemented by the subscription transport.
|
|
309
|
+
* @see https://github.com/graphql/graphql-over-http/blob/main/rfcs/GraphQLOverWebSocket.md
|
|
310
|
+
*/
|
|
311
|
+
const GRAPHQL_WEBSOCKET_SUBPROTOCOL = 'graphql-transport-ws'
|
|
312
|
+
|
|
313
|
+
function includesGraphQLProtocol(
|
|
314
|
+
protocols: string | Array<string> | null | undefined,
|
|
315
|
+
): boolean {
|
|
316
|
+
if (protocols == null) {
|
|
317
|
+
return false
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Support both the WebSocket constructor argument (a protocol string
|
|
321
|
+
// or a list of protocol strings) and the `Sec-WebSocket-Protocol`
|
|
322
|
+
// request header (a comma-separated list).
|
|
323
|
+
const requestedProtocols =
|
|
324
|
+
typeof protocols === 'string' ? protocols.split(',') : protocols
|
|
325
|
+
|
|
326
|
+
return requestedProtocols.some((protocol) => {
|
|
327
|
+
return protocol.trim() === GRAPHQL_WEBSOCKET_SUBPROTOCOL
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* A WebSocket handler that only matches connections that requested the
|
|
333
|
+
* `graphql-transport-ws` protocol. Connections without it (e.g.
|
|
334
|
+
* arbitrary non-GraphQL WebSockets whose URL matched a permissive
|
|
335
|
+
* endpoint like a wildcard link) are left unhandled so they follow the
|
|
336
|
+
* regular unhandled connection flow (warnings, passthrough).
|
|
337
|
+
*/
|
|
338
|
+
abstract class GraphQLWebSocketHandler extends WebSocketHandler {
|
|
339
|
+
public async run(
|
|
340
|
+
connection: WebSocketConnectionEventData,
|
|
341
|
+
resolutionContext?: WebSocketResolutionContext,
|
|
342
|
+
): Promise<WebSocketHandlerConnection | null> {
|
|
343
|
+
if (!includesGraphQLProtocol(connection.info.protocols)) {
|
|
344
|
+
return null
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return super.run(connection, resolutionContext)
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* A WebSocket handler implementing the `graphql-transport-ws` protocol
|
|
353
|
+
* session for a single GraphQL endpoint. One transport is shared across
|
|
354
|
+
* all subscription handlers created from the same `graphql.link()` call
|
|
355
|
+
* (attached to each of them as a sibling handler).
|
|
356
|
+
*
|
|
357
|
+
* The transport owns the protocol/session concerns: connection
|
|
358
|
+
* acknowledgement, keep-alive, the per-connection registry of active
|
|
359
|
+
* subscriptions, and dispatching parsed `subscribe` operations to the
|
|
360
|
+
* matching subscription handler.
|
|
361
|
+
*/
|
|
362
|
+
export class GraphQLSubscriptionTransportHandler extends GraphQLWebSocketHandler {
|
|
363
|
+
/**
|
|
364
|
+
* Register the given handler as a subscriber to the GraphQL
|
|
365
|
+
* subscriptions on the given WebSocket connection. Subscribers are
|
|
366
|
+
* dispatched in registration order, which follows the handlers
|
|
367
|
+
* resolution order (runtime handlers take precedence).
|
|
368
|
+
*/
|
|
369
|
+
public subscribe(
|
|
370
|
+
connection: WebSocketHandlerConnection,
|
|
371
|
+
handler: WebSocketHandler,
|
|
372
|
+
subscriber: GraphQLSubscriptionSubscriber,
|
|
373
|
+
): void {
|
|
374
|
+
const transportConnection = this.#getOrCreateConnection(connection)
|
|
375
|
+
transportConnection.subscribers.set(handler, {
|
|
376
|
+
transport: this,
|
|
377
|
+
subscriber,
|
|
378
|
+
})
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
public getConnection(
|
|
382
|
+
clientId: string,
|
|
383
|
+
): GraphQLSubscriptionConnection | undefined {
|
|
384
|
+
return connections.get(clientId)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
public async run(
|
|
388
|
+
connection: WebSocketConnectionEventData,
|
|
389
|
+
resolutionContext?: WebSocketResolutionContext,
|
|
390
|
+
): Promise<WebSocketHandlerConnection | null> {
|
|
391
|
+
const handlerConnection = await super.run(connection, resolutionContext)
|
|
392
|
+
|
|
393
|
+
// Capture the network frame events reference for this connection.
|
|
394
|
+
// The transport emits life-cycle events (e.g. "graphql:subscription")
|
|
395
|
+
// long after the run: whenever the client sends a "subscribe" message.
|
|
396
|
+
if (handlerConnection) {
|
|
397
|
+
const transportConnection = this.#getOrCreateConnection(handlerConnection)
|
|
398
|
+
|
|
399
|
+
// Never overwrite the events of a session shared with another
|
|
400
|
+
// transport: only the frame that resolved it provides them.
|
|
401
|
+
if (resolutionContext?.events) {
|
|
402
|
+
transportConnection.events = resolutionContext.events
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return handlerConnection
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* End the given subscription without notifying the client. Used when
|
|
411
|
+
* the subscription has already been terminated over the wire (e.g. the
|
|
412
|
+
* original server completed it and that frame reached the client).
|
|
413
|
+
*/
|
|
414
|
+
public endSubscription(args: {
|
|
415
|
+
clientId: string
|
|
416
|
+
subscriptionId: string
|
|
417
|
+
}): void {
|
|
418
|
+
const connection = connections.get(args.clientId)
|
|
419
|
+
|
|
420
|
+
if (connection) {
|
|
421
|
+
this.#endSubscription(connection, args.subscriptionId)
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Schedule a cleanup to run once the given subscription ends.
|
|
427
|
+
*
|
|
428
|
+
* @note If the subscription has already ended by the time this is
|
|
429
|
+
* called, the cleanup runs immediately. The resolver can no longer
|
|
430
|
+
* affect that subscription, so there is nothing left to wait for.
|
|
431
|
+
*/
|
|
432
|
+
public finalize(args: {
|
|
433
|
+
clientId: string
|
|
434
|
+
subscriptionId: string
|
|
435
|
+
cleanup: GraphQLSubscriptionCleanup
|
|
436
|
+
}): void {
|
|
437
|
+
const cleanups = connections
|
|
438
|
+
.get(args.clientId)
|
|
439
|
+
?.subscriptions.get(args.subscriptionId)
|
|
440
|
+
|
|
441
|
+
if (cleanups) {
|
|
442
|
+
cleanups.push(args.cleanup)
|
|
443
|
+
return
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
this.#exhaustCleanups([args.cleanup])
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
async #endAllSubscriptions(
|
|
450
|
+
connection: GraphQLSubscriptionConnection,
|
|
451
|
+
): Promise<void> {
|
|
452
|
+
const pendingCleanups: Array<Promise<void>> = []
|
|
453
|
+
|
|
454
|
+
for (const subscriptionId of connection.subscriptions.keys()) {
|
|
455
|
+
pendingCleanups.push(this.#endSubscription(connection, subscriptionId))
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
await Promise.all(pendingCleanups)
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* End the given subscription and run the cleanups scheduled for it.
|
|
463
|
+
*
|
|
464
|
+
* This is the single exit point for every way a subscription can end:
|
|
465
|
+
* completed by the mock, by the client, or by the original server;
|
|
466
|
+
* terminated with errors; dropped when the client disconnects; or
|
|
467
|
+
* detached from its resolver when the handlers are reset. Ending an
|
|
468
|
+
* already-ended subscription is a no-op, so the cleanups are
|
|
469
|
+
* guaranteed to run at most once.
|
|
470
|
+
*/
|
|
471
|
+
#endSubscription(
|
|
472
|
+
connection: GraphQLSubscriptionConnection,
|
|
473
|
+
subscriptionId: string,
|
|
474
|
+
): Promise<void> {
|
|
475
|
+
const cleanups = connection.subscriptions.get(subscriptionId)
|
|
476
|
+
|
|
477
|
+
if (!cleanups) {
|
|
478
|
+
return Promise.resolve()
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
connection.subscriptions.delete(subscriptionId)
|
|
482
|
+
return this.#exhaustCleanups(cleanups)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Run the given cleanups as LIFO, consistently with `finalize()` in
|
|
487
|
+
* the request handlers. Cleanups are detached from the subscription
|
|
488
|
+
* life-cycle: nothing awaits them, so this must never reject.
|
|
489
|
+
*/
|
|
490
|
+
async #exhaustCleanups(
|
|
491
|
+
cleanups: Array<GraphQLSubscriptionCleanup>,
|
|
492
|
+
): Promise<void> {
|
|
493
|
+
const errors: Array<Error> = []
|
|
494
|
+
|
|
495
|
+
for (let index = cleanups.length - 1; index >= 0; index--) {
|
|
496
|
+
try {
|
|
497
|
+
await cleanups[index]()
|
|
498
|
+
} catch (error) {
|
|
499
|
+
if (error instanceof Error) {
|
|
500
|
+
errors.push(error)
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (errors.length > 0) {
|
|
506
|
+
devUtils.error(
|
|
507
|
+
'Failed to execute the cleanup for a GraphQL subscription to "%s". Please see the original error below.',
|
|
508
|
+
this.url.toString(),
|
|
509
|
+
new AggregateError(errors),
|
|
510
|
+
)
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Send a `next` message with the given payload to the subscription.
|
|
516
|
+
*/
|
|
517
|
+
public publish(args: {
|
|
518
|
+
clientId: string
|
|
519
|
+
subscriptionId: string
|
|
520
|
+
payload: GraphQLSubscriptionPayload
|
|
521
|
+
}): void {
|
|
522
|
+
const connection = this.#getConnectionForSubscription({
|
|
523
|
+
clientId: args.clientId,
|
|
524
|
+
subscriptionId: args.subscriptionId,
|
|
525
|
+
intent: 'publish to',
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
if (!connection) {
|
|
529
|
+
return
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
connection.client.send(
|
|
533
|
+
createNextMessage({
|
|
534
|
+
id: args.subscriptionId,
|
|
535
|
+
payload: args.payload,
|
|
536
|
+
}),
|
|
537
|
+
)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Send a terminal `error` message to the subscription and
|
|
542
|
+
* removes it from the registry of active subscriptions.
|
|
543
|
+
*/
|
|
544
|
+
public error(args: {
|
|
545
|
+
clientId: string
|
|
546
|
+
subscriptionId: string
|
|
547
|
+
errors: ReadonlyArray<Partial<GraphQLError>>
|
|
548
|
+
}): void {
|
|
549
|
+
const connection = this.#getConnectionForSubscription({
|
|
550
|
+
clientId: args.clientId,
|
|
551
|
+
subscriptionId: args.subscriptionId,
|
|
552
|
+
intent: 'error',
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
if (!connection) {
|
|
556
|
+
return
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
connection.client.send(
|
|
560
|
+
createErrorMessage({
|
|
561
|
+
id: args.subscriptionId,
|
|
562
|
+
payload: args.errors,
|
|
563
|
+
}),
|
|
564
|
+
)
|
|
565
|
+
this.#endSubscription(connection, args.subscriptionId)
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Send a `complete` message to the subscription and removes it
|
|
570
|
+
* from the registry of active subscriptions.
|
|
571
|
+
*/
|
|
572
|
+
public complete(args: { clientId: string; subscriptionId: string }): void {
|
|
573
|
+
const connection = this.#getConnectionForSubscription({
|
|
574
|
+
clientId: args.clientId,
|
|
575
|
+
subscriptionId: args.subscriptionId,
|
|
576
|
+
intent: 'complete',
|
|
577
|
+
})
|
|
578
|
+
|
|
579
|
+
if (!connection) {
|
|
580
|
+
return
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
connection.client.send(createCompleteMessage({ id: args.subscriptionId }))
|
|
584
|
+
this.#endSubscription(connection, args.subscriptionId)
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Drop this transport's subscribers and active subscriptions from the
|
|
589
|
+
* sessions it participates in. The sessions themselves are left intact:
|
|
590
|
+
* they are shared with the other transports of the same connection and
|
|
591
|
+
* own the protocol listeners for as long as the client stays connected.
|
|
592
|
+
*
|
|
593
|
+
* @note This method is invoked automatically when the handlers
|
|
594
|
+
* controller resets the handlers (e.g. `server.resetHandlers()`).
|
|
595
|
+
*/
|
|
596
|
+
public reset(): void {
|
|
597
|
+
for (const connection of connections.values()) {
|
|
598
|
+
let ownsConnection = false
|
|
599
|
+
|
|
600
|
+
for (const [handler, entry] of connection.subscribers) {
|
|
601
|
+
if (entry.transport === this) {
|
|
602
|
+
connection.subscribers.delete(handler)
|
|
603
|
+
ownsConnection = true
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Resetting the handlers detaches the resolvers from their
|
|
608
|
+
// subscriptions, so run their cleanups instead of dropping them.
|
|
609
|
+
if (ownsConnection) {
|
|
610
|
+
this.#endAllSubscriptions(connection)
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Forget the sessions of this transport, ending their subscriptions.
|
|
617
|
+
* @note This method is invoked automatically when the network is
|
|
618
|
+
* disabled (e.g. `server.close()`).
|
|
619
|
+
*/
|
|
620
|
+
public dispose(): MaybePromise<void> {
|
|
621
|
+
const pendingCleanups: Array<Promise<void>> = []
|
|
622
|
+
|
|
623
|
+
for (const [clientId, connection] of connections) {
|
|
624
|
+
for (const [handler, entry] of connection.subscribers) {
|
|
625
|
+
if (entry.transport === this) {
|
|
626
|
+
connection.subscribers.delete(handler)
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// A session is shared by all the transports of the same endpoint,
|
|
631
|
+
// so it's only torn down once the last of them is disposed of.
|
|
632
|
+
if (connection.subscribers.size === 0) {
|
|
633
|
+
pendingCleanups.push(this.#endAllSubscriptions(connection))
|
|
634
|
+
connections.delete(clientId)
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (pendingCleanups.length > 0) {
|
|
639
|
+
return Promise.all(pendingCleanups).then(() => {})
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* @note The transport is the sole owner of logging for GraphQL
|
|
645
|
+
* subscription connections. It logs parsed `graphql-transport-ws`
|
|
646
|
+
* frames instead of raw WebSocket messages.
|
|
647
|
+
*/
|
|
648
|
+
public log(connection: WebSocketConnectionEventData): () => void {
|
|
649
|
+
return attachGraphQLSubscriptionLogger(connection)
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
protected [kConnect](connection: WebSocketHandlerConnection): boolean {
|
|
653
|
+
this.#getOrCreateConnection(connection)
|
|
654
|
+
return true
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
#getOrCreateConnection(
|
|
658
|
+
connection: WebSocketHandlerConnection,
|
|
659
|
+
): GraphQLSubscriptionConnection {
|
|
660
|
+
const { client } = connection
|
|
661
|
+
const existingConnection = connections.get(client.id)
|
|
662
|
+
|
|
663
|
+
if (existingConnection) {
|
|
664
|
+
return existingConnection
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const transportConnection: GraphQLSubscriptionConnection = {
|
|
668
|
+
client: connection.client,
|
|
669
|
+
server: connection.server,
|
|
670
|
+
subscribers: new Map(),
|
|
671
|
+
subscriptions: new Map(),
|
|
672
|
+
}
|
|
673
|
+
connections.set(client.id, transportConnection)
|
|
674
|
+
|
|
675
|
+
// Bind the protocol listeners alongside the session that owns them.
|
|
676
|
+
// Creating the session and binding its listeners is a single step, so
|
|
677
|
+
// they are guaranteed to be bound exactly once per connection no matter
|
|
678
|
+
// how many transports end up sharing this session.
|
|
679
|
+
client.addEventListener('message', (event) => {
|
|
680
|
+
this.#handleClientMessage(client.id, event.data)
|
|
681
|
+
})
|
|
682
|
+
|
|
683
|
+
client.addEventListener('close', () => {
|
|
684
|
+
// The resolvers can no longer affect any of the subscriptions
|
|
685
|
+
// on this connection once the client disconnects.
|
|
686
|
+
this.#endAllSubscriptions(transportConnection)
|
|
687
|
+
connections.delete(client.id)
|
|
688
|
+
})
|
|
689
|
+
|
|
690
|
+
return transportConnection
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
#getConnectionForSubscription(args: {
|
|
694
|
+
clientId: string
|
|
695
|
+
subscriptionId: string
|
|
696
|
+
intent: string
|
|
697
|
+
}): GraphQLSubscriptionConnection | undefined {
|
|
698
|
+
const connection = connections.get(args.clientId)
|
|
699
|
+
|
|
700
|
+
if (!connection || !connection.subscriptions.has(args.subscriptionId)) {
|
|
701
|
+
devUtils.warn(
|
|
702
|
+
'Failed to %s the GraphQL subscription "%s": the subscription is no longer active.',
|
|
703
|
+
args.intent,
|
|
704
|
+
args.subscriptionId,
|
|
705
|
+
)
|
|
706
|
+
return undefined
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
return connection
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
#handleClientMessage(clientId: string, data: WebSocketData): void {
|
|
713
|
+
const connection = connections.get(clientId)
|
|
714
|
+
|
|
715
|
+
if (!connection) {
|
|
716
|
+
return
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
const message =
|
|
720
|
+
parseGraphQLWebSocketMessage<GraphQLWebSocketClientMessage>(data)
|
|
721
|
+
|
|
722
|
+
if (!message) {
|
|
723
|
+
return
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
switch (message.type) {
|
|
727
|
+
case 'connection_init': {
|
|
728
|
+
// Preserve the initialization payload (e.g. the client's
|
|
729
|
+
// credentials) so passthrough can replay it to the server.
|
|
730
|
+
connection.connectionParams = message.payload
|
|
731
|
+
connection.client.send(createAcknowledgeMessage())
|
|
732
|
+
break
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
case 'ping': {
|
|
736
|
+
connection.client.send(createPongMessage())
|
|
737
|
+
break
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
case 'subscribe': {
|
|
741
|
+
this.#handleSubscribeMessage(connection, message)
|
|
742
|
+
break
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
case 'complete': {
|
|
746
|
+
this.#endSubscription(connection, message.id)
|
|
747
|
+
break
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
#handleSubscribeMessage(
|
|
753
|
+
connection: GraphQLSubscriptionConnection,
|
|
754
|
+
message: GraphQLWebSocketSubscribeMessage,
|
|
755
|
+
): void {
|
|
756
|
+
let node: ParsedGraphQLQuery
|
|
757
|
+
|
|
758
|
+
try {
|
|
759
|
+
node = parseDocumentNode(
|
|
760
|
+
parse(message.payload.query),
|
|
761
|
+
message.payload.operationName,
|
|
762
|
+
)
|
|
763
|
+
} catch (error) {
|
|
764
|
+
devUtils.warn(
|
|
765
|
+
'Failed to intercept a GraphQL subscription to "%s": the subscription query is not a valid GraphQL document.\n\n%s',
|
|
766
|
+
toPublicUrl(connection.client.url),
|
|
767
|
+
error,
|
|
768
|
+
)
|
|
769
|
+
return
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (node.operationType !== OperationTypeNode.SUBSCRIPTION) {
|
|
773
|
+
devUtils.warn(
|
|
774
|
+
'Intercepted a GraphQL %s "%s" over WebSocket: only subscription operations are supported over the WebSocket transport.',
|
|
775
|
+
node.operationType,
|
|
776
|
+
node.operationName || '(anonymous)',
|
|
777
|
+
)
|
|
778
|
+
return
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// Register the subscription before dispatching it so the resolver
|
|
782
|
+
// can publish to it synchronously.
|
|
783
|
+
connection.subscriptions.set(message.id, [])
|
|
784
|
+
|
|
785
|
+
for (const { subscriber } of connection.subscribers.values()) {
|
|
786
|
+
if (subscriber({ node, message })) {
|
|
787
|
+
this.#emitSubscriptionEvent(connection, node, message)
|
|
788
|
+
return
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
devUtils.warn(
|
|
793
|
+
'Intercepted a GraphQL subscription "%s" to "%s" that has no matching subscription handler. If you wish to mock this subscription, create a subscription handler for it.',
|
|
794
|
+
node.operationName || '(anonymous)',
|
|
795
|
+
toPublicUrl(connection.client.url),
|
|
796
|
+
)
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* Emit the "graphql:subscription" life-cycle event on the network.
|
|
801
|
+
* The event is emitted once the subscription has been established:
|
|
802
|
+
* matched by a subscription handler and resolved.
|
|
803
|
+
*/
|
|
804
|
+
#emitSubscriptionEvent(
|
|
805
|
+
connection: GraphQLSubscriptionConnection,
|
|
806
|
+
node: ParsedGraphQLQuery,
|
|
807
|
+
message: GraphQLWebSocketSubscribeMessage,
|
|
808
|
+
): void {
|
|
809
|
+
// Anonymous subscriptions can never match a subscription handler.
|
|
810
|
+
if (!connection.events || !node.operationName) {
|
|
811
|
+
return
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
connection.events.emit(
|
|
815
|
+
new GraphQLSubscriptionEvent({
|
|
816
|
+
operationName: node.operationName,
|
|
817
|
+
query: message.payload.query,
|
|
818
|
+
variables: { ...message.payload.variables },
|
|
819
|
+
request: createUpgradeRequest(connection.client.url),
|
|
820
|
+
}),
|
|
821
|
+
)
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
export type GraphQLSubscriptionName<
|
|
826
|
+
Query extends GraphQLQuery = GraphQLQuery,
|
|
827
|
+
Variables extends GraphQLVariables = GraphQLVariables,
|
|
828
|
+
> = GraphQLHandlerNameSelector | DocumentTypeDecoration<Query, Variables>
|
|
829
|
+
|
|
830
|
+
export interface GraphQLSubscriptionResolverInfo<
|
|
831
|
+
Query extends GraphQLQuery = GraphQLQuery,
|
|
832
|
+
Variables extends GraphQLVariables = GraphQLVariables,
|
|
833
|
+
> {
|
|
834
|
+
/**
|
|
835
|
+
* Path parameters parsed from the WebSocket connection URL.
|
|
836
|
+
*/
|
|
837
|
+
params: PathParams
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* The name of the intercepted operation.
|
|
841
|
+
*/
|
|
842
|
+
operationName: string
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* Intercepted GraphQL subscription.
|
|
846
|
+
*/
|
|
847
|
+
subscription: GraphQLSubscription<Query, Variables>
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* The request that established the WebSocket connection this
|
|
851
|
+
* subscription is multiplexed over.
|
|
852
|
+
*/
|
|
853
|
+
request: Request
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* Schedule a cleanup to run once this subscription ends and the
|
|
857
|
+
* resolver can no longer affect it: it has been completed (by the mock,
|
|
858
|
+
* the client, or the original server), terminated with errors, or the
|
|
859
|
+
* client has disconnected.
|
|
860
|
+
*
|
|
861
|
+
* @example
|
|
862
|
+
* api.subscription('OnCommentAdded', ({ subscription, finalize }) => {
|
|
863
|
+
* const interval = setInterval(() => subscription.publish(payload), 1000)
|
|
864
|
+
* finalize(() => clearInterval(interval))
|
|
865
|
+
* })
|
|
866
|
+
*/
|
|
867
|
+
finalize: ResponseResolverFinalizeFunction
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
export type GraphQLSubscriptionResolver<
|
|
871
|
+
Query extends GraphQLQuery = GraphQLQuery,
|
|
872
|
+
Variables extends GraphQLVariables = GraphQLVariables,
|
|
873
|
+
> = (info: GraphQLSubscriptionResolverInfo<Query, Variables>) => void
|
|
874
|
+
|
|
875
|
+
export interface GraphQLSubscriptionHandlerOptions {
|
|
876
|
+
/**
|
|
877
|
+
* Mark this handler as used after its first match.
|
|
878
|
+
* Used handlers do not match subsequent subscriptions.
|
|
879
|
+
*/
|
|
880
|
+
once?: boolean
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* A WebSocket handler intercepting GraphQL subscriptions by their
|
|
885
|
+
* operation name. Matching and resolution are delegated to it by the
|
|
886
|
+
* subscription transport (its sibling handler) so the first matching
|
|
887
|
+
* handler wins, respecting runtime handler overrides.
|
|
888
|
+
*/
|
|
889
|
+
export class GraphQLSubscriptionHandler<
|
|
890
|
+
Query extends GraphQLQuery = GraphQLQuery,
|
|
891
|
+
Variables extends GraphQLVariables = GraphQLVariables,
|
|
892
|
+
> extends GraphQLWebSocketHandler {
|
|
893
|
+
public info: GraphQLHandlerInfo
|
|
894
|
+
public isUsed: boolean
|
|
895
|
+
|
|
896
|
+
readonly #operationName: string | RegExp
|
|
897
|
+
readonly #transport: GraphQLSubscriptionTransportHandler
|
|
898
|
+
readonly #resolver: GraphQLSubscriptionResolver<Query, Variables>
|
|
899
|
+
readonly #options: GraphQLSubscriptionHandlerOptions
|
|
900
|
+
|
|
901
|
+
constructor(args: {
|
|
902
|
+
url: Path
|
|
903
|
+
operationName: GraphQLSubscriptionName<Query, Variables>
|
|
904
|
+
transport: GraphQLSubscriptionTransportHandler
|
|
905
|
+
resolver: GraphQLSubscriptionResolver<Query, Variables>
|
|
906
|
+
options?: GraphQLSubscriptionHandlerOptions
|
|
907
|
+
}) {
|
|
908
|
+
super(args.url)
|
|
909
|
+
|
|
910
|
+
// Create the same GraphQL handler info as request-based GraphQL
|
|
911
|
+
// handlers so this handler prints nicely during introspection
|
|
912
|
+
// (e.g. `server.listHandlers()`). This also normalizes `DocumentNode`
|
|
913
|
+
// and typed document predicates to plain operation names.
|
|
914
|
+
this.info = GraphQLHandler.parseGraphQLRequestInfo({
|
|
915
|
+
operationType: OperationTypeNode.SUBSCRIPTION,
|
|
916
|
+
predicate: args.operationName,
|
|
917
|
+
url: args.url,
|
|
918
|
+
})
|
|
919
|
+
|
|
920
|
+
const { operationName } = this.info
|
|
921
|
+
|
|
922
|
+
invariant(
|
|
923
|
+
typeof operationName !== 'function' && !isDocumentNode(operationName),
|
|
924
|
+
'Failed to create a GraphQL subscription handler: custom predicates are not supported for subscriptions',
|
|
925
|
+
)
|
|
926
|
+
|
|
927
|
+
this.#operationName = operationName
|
|
928
|
+
this.#transport = args.transport
|
|
929
|
+
this.#resolver = args.resolver
|
|
930
|
+
this.#options = args.options || {}
|
|
931
|
+
this.isUsed = false
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
public reset(): void {
|
|
935
|
+
this.isUsed = false
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* @note Individual subscription handlers stay silent. The subscription
|
|
940
|
+
* transport owns the GraphQL-aware logging for the entire connection
|
|
941
|
+
* (a logger is attached once per matching handler otherwise).
|
|
942
|
+
*/
|
|
943
|
+
public log(): () => void {
|
|
944
|
+
return function detachLogger() {}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
protected [kConnect](connection: WebSocketHandlerConnection): boolean {
|
|
948
|
+
this.#transport.subscribe(connection, this, (args) => {
|
|
949
|
+
return this.#handleSubscribe(connection, args)
|
|
950
|
+
})
|
|
951
|
+
|
|
952
|
+
return true
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
#handleSubscribe(
|
|
956
|
+
connection: WebSocketHandlerConnection,
|
|
957
|
+
args: {
|
|
958
|
+
node: ParsedGraphQLQuery
|
|
959
|
+
message: GraphQLWebSocketSubscribeMessage
|
|
960
|
+
},
|
|
961
|
+
): boolean {
|
|
962
|
+
if (this.#options.once && this.isUsed) {
|
|
963
|
+
return false
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
const { operationName } = args.node
|
|
967
|
+
|
|
968
|
+
if (!operationName || !this.#matchesOperationName(operationName)) {
|
|
969
|
+
return false
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
this.isUsed = true
|
|
973
|
+
|
|
974
|
+
const subscription = new GraphQLSubscription<Query, Variables>({
|
|
975
|
+
message: args.message,
|
|
976
|
+
clientId: connection.client.id,
|
|
977
|
+
transport: this.#transport,
|
|
978
|
+
})
|
|
979
|
+
|
|
980
|
+
this.#resolver({
|
|
981
|
+
params: connection.params,
|
|
982
|
+
operationName,
|
|
983
|
+
subscription,
|
|
984
|
+
request: createUpgradeRequest(connection.client.url),
|
|
985
|
+
finalize: (cleanup) => {
|
|
986
|
+
this.#transport.finalize({
|
|
987
|
+
clientId: connection.client.id,
|
|
988
|
+
subscriptionId: subscription.id,
|
|
989
|
+
cleanup,
|
|
990
|
+
})
|
|
991
|
+
},
|
|
992
|
+
})
|
|
993
|
+
|
|
994
|
+
return true
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
#matchesOperationName(operationName: string): boolean {
|
|
998
|
+
if (this.#operationName instanceof RegExp) {
|
|
999
|
+
return this.#operationName.test(operationName)
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
return this.#operationName === operationName
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Representation of the intercepted GraphQL subscription.
|
|
1008
|
+
*/
|
|
1009
|
+
export class GraphQLSubscription<
|
|
1010
|
+
Query extends GraphQLQuery = GraphQLQuery,
|
|
1011
|
+
Variables extends GraphQLVariables = GraphQLVariables,
|
|
1012
|
+
> {
|
|
1013
|
+
public id: string
|
|
1014
|
+
public query: string
|
|
1015
|
+
public variables: Variables
|
|
1016
|
+
public extensions?: Record<string, unknown>
|
|
1017
|
+
|
|
1018
|
+
readonly #message: GraphQLWebSocketSubscribeMessage
|
|
1019
|
+
readonly #clientId: string
|
|
1020
|
+
readonly #transport: GraphQLSubscriptionTransportHandler
|
|
1021
|
+
|
|
1022
|
+
constructor(args: {
|
|
1023
|
+
message: GraphQLWebSocketSubscribeMessage
|
|
1024
|
+
clientId: string
|
|
1025
|
+
transport: GraphQLSubscriptionTransportHandler
|
|
1026
|
+
}) {
|
|
1027
|
+
this.id = args.message.id
|
|
1028
|
+
this.query = args.message.payload.query
|
|
1029
|
+
this.variables = (args.message.payload.variables || {}) as Variables
|
|
1030
|
+
this.extensions = args.message.payload.extensions
|
|
1031
|
+
|
|
1032
|
+
this.#message = args.message
|
|
1033
|
+
this.#clientId = args.clientId
|
|
1034
|
+
this.#transport = args.transport
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* Publish an execution result to the subscribed client.
|
|
1039
|
+
*
|
|
1040
|
+
* @example
|
|
1041
|
+
* subscription.publish({
|
|
1042
|
+
* data: {
|
|
1043
|
+
* postAdded: {
|
|
1044
|
+
* id: 'abc-123'
|
|
1045
|
+
* }
|
|
1046
|
+
* }
|
|
1047
|
+
* })
|
|
1048
|
+
*/
|
|
1049
|
+
public publish(payload: GraphQLSubscriptionPayload<Query>): void {
|
|
1050
|
+
this.#transport.publish({
|
|
1051
|
+
clientId: this.#clientId,
|
|
1052
|
+
subscriptionId: this.id,
|
|
1053
|
+
payload,
|
|
1054
|
+
})
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Use the given `Iterable` or `AsyncIterable` as the source
|
|
1059
|
+
* of data for this subscription. Whenever the iterable yields a
|
|
1060
|
+
* value, it gets published to this subscription.
|
|
1061
|
+
*
|
|
1062
|
+
* @example
|
|
1063
|
+
* subscription.from(async function* () {
|
|
1064
|
+
* yield { text: 'hello world' }
|
|
1065
|
+
* })
|
|
1066
|
+
*/
|
|
1067
|
+
public async from(
|
|
1068
|
+
source: Iterable<Query> | AsyncIterable<Query>,
|
|
1069
|
+
): Promise<void> {
|
|
1070
|
+
for await (const data of source) {
|
|
1071
|
+
this.publish({ data })
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Terminate this subscription with the given errors.
|
|
1077
|
+
*
|
|
1078
|
+
* @example
|
|
1079
|
+
* subscription.error([{ message: 'Something went wrong' }])
|
|
1080
|
+
*/
|
|
1081
|
+
public error(errors: ReadonlyArray<Partial<GraphQLError>>): void {
|
|
1082
|
+
this.#transport.error({
|
|
1083
|
+
clientId: this.#clientId,
|
|
1084
|
+
subscriptionId: this.id,
|
|
1085
|
+
errors,
|
|
1086
|
+
})
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
/**
|
|
1090
|
+
* Marks this subscription as complete.
|
|
1091
|
+
*
|
|
1092
|
+
* @example
|
|
1093
|
+
* subscription.complete()
|
|
1094
|
+
*/
|
|
1095
|
+
public complete(): void {
|
|
1096
|
+
this.#transport.complete({
|
|
1097
|
+
clientId: this.#clientId,
|
|
1098
|
+
subscriptionId: this.id,
|
|
1099
|
+
})
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* Perform this GraphQL subscription as-is.
|
|
1104
|
+
* This establishes a connection to the actual server, replays
|
|
1105
|
+
* the intercepted subscription, and forwards the server payloads
|
|
1106
|
+
* to the GraphQL client. You can intercept, modify, or prevent
|
|
1107
|
+
* any of the original server messages.
|
|
1108
|
+
*
|
|
1109
|
+
* @example
|
|
1110
|
+
* const postAddedSubscription = subscription.passthrough()
|
|
1111
|
+
* postAddedSubscription.addEventListener('next', (event) => {
|
|
1112
|
+
* event.preventDefault()
|
|
1113
|
+
* event.data.payload.data.postAdded.id = 'mock-id'
|
|
1114
|
+
* subscription.publish(event.data.payload)
|
|
1115
|
+
* })
|
|
1116
|
+
*/
|
|
1117
|
+
public passthrough(): GraphQLPassthroughSubscription {
|
|
1118
|
+
const connection = this.#transport.getConnection(this.#clientId)
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* @note One can only call this method inside the GraphQL subscription
|
|
1122
|
+
* handler. By that point, the WebSocket connection has been established
|
|
1123
|
+
* and intercepted so the connection reference is guaranteed.
|
|
1124
|
+
*/
|
|
1125
|
+
invariant(
|
|
1126
|
+
connection,
|
|
1127
|
+
'Failed to passthrough the GraphQL subscription ("%s"): the underlying WebSocket connection is closed',
|
|
1128
|
+
this.query,
|
|
1129
|
+
)
|
|
1130
|
+
|
|
1131
|
+
return new GraphQLPassthroughSubscription({
|
|
1132
|
+
server: connection.server,
|
|
1133
|
+
message: this.#message,
|
|
1134
|
+
upstreamSession: ensureUpstreamSession(connection),
|
|
1135
|
+
onTerminate: () => {
|
|
1136
|
+
this.#transport.endSubscription({
|
|
1137
|
+
clientId: this.#clientId,
|
|
1138
|
+
subscriptionId: this.id,
|
|
1139
|
+
})
|
|
1140
|
+
},
|
|
1141
|
+
})
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
export type GraphQLPassthroughSubscriptionEventMap = {
|
|
1146
|
+
connection_ack: TypedEvent
|
|
1147
|
+
next: TypedEvent<GraphQLWebSocketNextMessage>
|
|
1148
|
+
error: TypedEvent<GraphQLWebSocketErrorMessage>
|
|
1149
|
+
complete: TypedEvent<GraphQLWebSocketCompleteMessage>
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
/**
|
|
1153
|
+
* Representation of a GraphQL subscription to the actual server.
|
|
1154
|
+
* You interface with this object from the client's perspective.
|
|
1155
|
+
*/
|
|
1156
|
+
export class GraphQLPassthroughSubscription {
|
|
1157
|
+
readonly #server: WebSocketServerHandle
|
|
1158
|
+
readonly #message: GraphQLWebSocketSubscribeMessage
|
|
1159
|
+
readonly #emitter: Emitter<GraphQLPassthroughSubscriptionEventMap>
|
|
1160
|
+
readonly #abortController: AbortController
|
|
1161
|
+
readonly #onTerminate: () => void
|
|
1162
|
+
|
|
1163
|
+
constructor(args: {
|
|
1164
|
+
server: WebSocketServerHandle
|
|
1165
|
+
message: GraphQLWebSocketSubscribeMessage
|
|
1166
|
+
upstreamSession: Promise<void>
|
|
1167
|
+
onTerminate: () => void
|
|
1168
|
+
}) {
|
|
1169
|
+
this.#server = args.server
|
|
1170
|
+
this.#message = args.message
|
|
1171
|
+
this.#onTerminate = args.onTerminate
|
|
1172
|
+
this.#emitter = new Emitter()
|
|
1173
|
+
|
|
1174
|
+
// An abort controller responsible for removing the server event
|
|
1175
|
+
// listeners once the subscription is unsubscribed.
|
|
1176
|
+
this.#abortController = new AbortController()
|
|
1177
|
+
|
|
1178
|
+
// Replay this subscription once the shared upstream session is
|
|
1179
|
+
// established, so the server can authorize this client first.
|
|
1180
|
+
args.upstreamSession.then(() => {
|
|
1181
|
+
if (!this.#abortController.signal.aborted) {
|
|
1182
|
+
this.#server.send(JSON.stringify(this.#message))
|
|
1183
|
+
}
|
|
1184
|
+
})
|
|
1185
|
+
|
|
1186
|
+
this.#server.addEventListener(
|
|
1187
|
+
'message',
|
|
1188
|
+
(event) => {
|
|
1189
|
+
const message =
|
|
1190
|
+
parseGraphQLWebSocketMessage<GraphQLWebSocketServerMessage>(
|
|
1191
|
+
event.data,
|
|
1192
|
+
)
|
|
1193
|
+
|
|
1194
|
+
if (!message) {
|
|
1195
|
+
return
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
switch (message.type) {
|
|
1199
|
+
case 'connection_ack': {
|
|
1200
|
+
event.preventDefault()
|
|
1201
|
+
this.#emitter.emit(new TypedEvent('connection_ack'))
|
|
1202
|
+
break
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
case 'next': {
|
|
1206
|
+
if (message.id !== this.#message.id) {
|
|
1207
|
+
break
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
const nextEvent = new TypedEvent('next', { data: message })
|
|
1211
|
+
this.#emitter.emit(nextEvent)
|
|
1212
|
+
|
|
1213
|
+
if (nextEvent.defaultPrevented) {
|
|
1214
|
+
event.preventDefault()
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
break
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
case 'error': {
|
|
1221
|
+
if (message.id !== this.#message.id) {
|
|
1222
|
+
break
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
const errorEvent = new TypedEvent('error', { data: message })
|
|
1226
|
+
this.#emitter.emit(errorEvent)
|
|
1227
|
+
|
|
1228
|
+
if (errorEvent.defaultPrevented) {
|
|
1229
|
+
event.preventDefault()
|
|
1230
|
+
break
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// The original server terminated the subscription and that
|
|
1234
|
+
// frame reaches the client, so the subscription ends here.
|
|
1235
|
+
// A prevented frame means the mock took over instead.
|
|
1236
|
+
this.#onTerminate()
|
|
1237
|
+
break
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
case 'complete': {
|
|
1241
|
+
if (message.id !== this.#message.id) {
|
|
1242
|
+
break
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
const completeEvent = new TypedEvent('complete', { data: message })
|
|
1246
|
+
this.#emitter.emit(completeEvent)
|
|
1247
|
+
|
|
1248
|
+
if (completeEvent.defaultPrevented) {
|
|
1249
|
+
event.preventDefault()
|
|
1250
|
+
break
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
this.#onTerminate()
|
|
1254
|
+
break
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
},
|
|
1258
|
+
{ signal: this.#abortController.signal },
|
|
1259
|
+
)
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* Add an event listener to the given GraphQL subscription event.
|
|
1264
|
+
*
|
|
1265
|
+
* @example
|
|
1266
|
+
* const onPostAddedSubscription = subscription.passthrough()
|
|
1267
|
+
* onPostAddedSubscription.addEventListener('next', (event) => {
|
|
1268
|
+
* console.log(event.data)
|
|
1269
|
+
* // { id, payload, ... }
|
|
1270
|
+
* })
|
|
1271
|
+
*/
|
|
1272
|
+
public addEventListener<
|
|
1273
|
+
EventType extends keyof GraphQLPassthroughSubscriptionEventMap & string,
|
|
1274
|
+
>(
|
|
1275
|
+
event: EventType,
|
|
1276
|
+
listener: Emitter.Listener<
|
|
1277
|
+
Emitter<GraphQLPassthroughSubscriptionEventMap>,
|
|
1278
|
+
EventType
|
|
1279
|
+
>,
|
|
1280
|
+
): void {
|
|
1281
|
+
this.#emitter.on(event, listener, {
|
|
1282
|
+
signal: this.#abortController.signal,
|
|
1283
|
+
})
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
/**
|
|
1287
|
+
* Unsubscribe from this passthrough GraphQL subscription.
|
|
1288
|
+
* This stops this subscription on the original server.
|
|
1289
|
+
*
|
|
1290
|
+
* @note Unsubscribing from the original subscription has no
|
|
1291
|
+
* effect on the intercepted `subscription` object.
|
|
1292
|
+
*
|
|
1293
|
+
* @example
|
|
1294
|
+
* const onPostAddedSubscription = subscription.passthrough()
|
|
1295
|
+
* onPostAddedSubscription.unsubscribe()
|
|
1296
|
+
*/
|
|
1297
|
+
public unsubscribe(): void {
|
|
1298
|
+
this.#abortController.abort()
|
|
1299
|
+
this.#emitter.removeAllListeners()
|
|
1300
|
+
|
|
1301
|
+
/**
|
|
1302
|
+
* @note Complete this subscription instead of closing the server
|
|
1303
|
+
* connection. That connection is shared by every subscription of
|
|
1304
|
+
* this client, and closing it would terminate the unrelated ones.
|
|
1305
|
+
*/
|
|
1306
|
+
this.#server.send(createCompleteMessage({ id: this.#message.id }))
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
function logGraphQLFrame(args: {
|
|
1311
|
+
color: string
|
|
1312
|
+
label: string
|
|
1313
|
+
payload?: unknown
|
|
1314
|
+
}): void {
|
|
1315
|
+
const timestamp = getTimestamp({ milliseconds: true })
|
|
1316
|
+
|
|
1317
|
+
if (typeof args.payload === 'undefined') {
|
|
1318
|
+
// eslint-disable-next-line no-console
|
|
1319
|
+
console.log(
|
|
1320
|
+
devUtils.formatMessage(`${timestamp} %c${args.label}%c`),
|
|
1321
|
+
`color:${args.color}`,
|
|
1322
|
+
'color:inherit',
|
|
1323
|
+
)
|
|
1324
|
+
return
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
console.groupCollapsed(
|
|
1328
|
+
devUtils.formatMessage(`${timestamp} %c${args.label}%c`),
|
|
1329
|
+
`color:${args.color}`,
|
|
1330
|
+
'color:inherit',
|
|
1331
|
+
)
|
|
1332
|
+
// eslint-disable-next-line no-console
|
|
1333
|
+
console.log(args.payload)
|
|
1334
|
+
console.groupEnd()
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
/**
|
|
1338
|
+
* Attach a GraphQL-aware logger to the intercepted WebSocket connection.
|
|
1339
|
+
* Unlike the raw WebSocket logger, this logger prints parsed
|
|
1340
|
+
* `graphql-transport-ws` frames relevant to the subscription.
|
|
1341
|
+
*/
|
|
1342
|
+
function attachGraphQLSubscriptionLogger(
|
|
1343
|
+
connection: WebSocketConnectionEventData,
|
|
1344
|
+
): () => void {
|
|
1345
|
+
const { client } = connection
|
|
1346
|
+
const abortController = new AbortController()
|
|
1347
|
+
|
|
1348
|
+
logGraphQLFrame({
|
|
1349
|
+
color: colors.system,
|
|
1350
|
+
label: `GraphQL subscription connection ${toPublicUrl(client.url)}`,
|
|
1351
|
+
})
|
|
1352
|
+
|
|
1353
|
+
client.addEventListener(
|
|
1354
|
+
'message',
|
|
1355
|
+
(event) => {
|
|
1356
|
+
const message =
|
|
1357
|
+
parseGraphQLWebSocketMessage<GraphQLWebSocketClientMessage>(event.data)
|
|
1358
|
+
|
|
1359
|
+
if (!message) {
|
|
1360
|
+
return
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
switch (message.type) {
|
|
1364
|
+
case 'subscribe': {
|
|
1365
|
+
logGraphQLFrame({
|
|
1366
|
+
color: colors.outgoing,
|
|
1367
|
+
label: `subscribe (id: ${message.id})`,
|
|
1368
|
+
payload: message.payload,
|
|
1369
|
+
})
|
|
1370
|
+
break
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
case 'complete': {
|
|
1374
|
+
logGraphQLFrame({
|
|
1375
|
+
color: colors.outgoing,
|
|
1376
|
+
label: `complete (id: ${message.id})`,
|
|
1377
|
+
})
|
|
1378
|
+
break
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
},
|
|
1382
|
+
{ signal: abortController.signal },
|
|
1383
|
+
)
|
|
1384
|
+
|
|
1385
|
+
// Proxy `client.send` to log the frames published to the client
|
|
1386
|
+
// (`client.send` does not dispatch any observable events).
|
|
1387
|
+
const originalClientSend = client.send
|
|
1388
|
+
|
|
1389
|
+
client.send = new Proxy(client.send, {
|
|
1390
|
+
apply: (target, thisArg, args) => {
|
|
1391
|
+
const [data] = args
|
|
1392
|
+
const message =
|
|
1393
|
+
parseGraphQLWebSocketMessage<GraphQLWebSocketServerMessage>(data)
|
|
1394
|
+
|
|
1395
|
+
if (message) {
|
|
1396
|
+
switch (message.type) {
|
|
1397
|
+
case 'next': {
|
|
1398
|
+
logGraphQLFrame({
|
|
1399
|
+
color: colors.mocked,
|
|
1400
|
+
label: `next (id: ${message.id})`,
|
|
1401
|
+
payload: message.payload,
|
|
1402
|
+
})
|
|
1403
|
+
break
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
case 'error': {
|
|
1407
|
+
logGraphQLFrame({
|
|
1408
|
+
color: colors.mocked,
|
|
1409
|
+
label: `error (id: ${message.id})`,
|
|
1410
|
+
payload: message.payload,
|
|
1411
|
+
})
|
|
1412
|
+
break
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
case 'complete': {
|
|
1416
|
+
logGraphQLFrame({
|
|
1417
|
+
color: colors.mocked,
|
|
1418
|
+
label: `complete (id: ${message.id})`,
|
|
1419
|
+
})
|
|
1420
|
+
break
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
return Reflect.apply(target, thisArg, args)
|
|
1426
|
+
},
|
|
1427
|
+
})
|
|
1428
|
+
|
|
1429
|
+
return function detachLogger() {
|
|
1430
|
+
abortController.abort()
|
|
1431
|
+
client.send = originalClientSend
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
export type GraphQLSubscriptionHandlerFactory = <
|
|
1436
|
+
Query extends GraphQLQuery = GraphQLQuery,
|
|
1437
|
+
Variables extends GraphQLVariables = GraphQLVariables,
|
|
1438
|
+
>(
|
|
1439
|
+
operationName: GraphQLSubscriptionName<Query, Variables>,
|
|
1440
|
+
resolver: GraphQLSubscriptionResolver<Query, Variables>,
|
|
1441
|
+
options?: GraphQLSubscriptionHandlerOptions,
|
|
1442
|
+
) => GraphQLSubscriptionHandler<Query, Variables>
|
|
1443
|
+
|
|
1444
|
+
/**
|
|
1445
|
+
* Create a `subscription()` handler factory bound to the given GraphQL
|
|
1446
|
+
* endpoint. All subscription handlers created by the factory share a single
|
|
1447
|
+
* subscription transport and a single WebSocket upgrade handler, both
|
|
1448
|
+
* attached to each handler as siblings.
|
|
1449
|
+
*
|
|
1450
|
+
* @example
|
|
1451
|
+
* const subscription = createGraphQLSubscriptionHandler('https://api.example.com/graphql')
|
|
1452
|
+
* subscription('OnPostAdded', ({ subscription }) => {
|
|
1453
|
+
* subscription.publish({ data: { postAdded: { id: 'abc-123' } } })
|
|
1454
|
+
* })
|
|
1455
|
+
*/
|
|
1456
|
+
export function createGraphQLSubscriptionHandler(
|
|
1457
|
+
url: Path,
|
|
1458
|
+
): GraphQLSubscriptionHandlerFactory {
|
|
1459
|
+
const webSocketUrl =
|
|
1460
|
+
typeof url === 'string' ? url.replace(/^http/, 'ws') : url
|
|
1461
|
+
|
|
1462
|
+
const transport = new GraphQLSubscriptionTransportHandler(webSocketUrl)
|
|
1463
|
+
|
|
1464
|
+
// The `upgrade` request handler enables WebSocket interception in Node.js.
|
|
1465
|
+
// The same handler instance is shared between all subscription handlers
|
|
1466
|
+
// of this endpoint (sibling handlers are deduped by reference).
|
|
1467
|
+
const upgradeHandler = http.get(({ request }) => {
|
|
1468
|
+
return (
|
|
1469
|
+
request.headers.get('upgrade')?.toLowerCase() === 'websocket' &&
|
|
1470
|
+
includesGraphQLProtocol(request.headers.get('sec-websocket-protocol')) &&
|
|
1471
|
+
matchRequestUrl(new URL(resolveWebSocketUrl(request.url)), webSocketUrl)
|
|
1472
|
+
.matches
|
|
1473
|
+
)
|
|
1474
|
+
}, webSocketUpgrade)
|
|
1475
|
+
|
|
1476
|
+
return (operationName, resolver, options) => {
|
|
1477
|
+
const handler = new GraphQLSubscriptionHandler({
|
|
1478
|
+
url: webSocketUrl,
|
|
1479
|
+
operationName,
|
|
1480
|
+
transport,
|
|
1481
|
+
resolver,
|
|
1482
|
+
options,
|
|
1483
|
+
})
|
|
1484
|
+
|
|
1485
|
+
return attachSiblingHandlers(handler, [transport, upgradeHandler])
|
|
1486
|
+
}
|
|
1487
|
+
}
|