mockrtc 0.1.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.
Files changed (136) hide show
  1. package/.github/workflows/ci.yml +29 -0
  2. package/LICENSE +201 -0
  3. package/README.md +290 -0
  4. package/dist/admin-bin.d.ts +2 -0
  5. package/dist/admin-bin.js +67 -0
  6. package/dist/admin-bin.js.map +1 -0
  7. package/dist/client/mockrtc-client.d.ts +12 -0
  8. package/dist/client/mockrtc-client.js +67 -0
  9. package/dist/client/mockrtc-client.js.map +1 -0
  10. package/dist/client/mockrtc-remote-peer.d.ts +15 -0
  11. package/dist/client/mockrtc-remote-peer.js +246 -0
  12. package/dist/client/mockrtc-remote-peer.js.map +1 -0
  13. package/dist/control-channel.d.ts +8 -0
  14. package/dist/control-channel.js +11 -0
  15. package/dist/control-channel.js.map +1 -0
  16. package/dist/handling/handler-builder.d.ts +138 -0
  17. package/dist/handling/handler-builder.js +164 -0
  18. package/dist/handling/handler-builder.js.map +1 -0
  19. package/dist/handling/handler-step-definitions.d.ts +63 -0
  20. package/dist/handling/handler-step-definitions.js +123 -0
  21. package/dist/handling/handler-step-definitions.js.map +1 -0
  22. package/dist/handling/handler-steps.d.ts +48 -0
  23. package/dist/handling/handler-steps.js +218 -0
  24. package/dist/handling/handler-steps.js.map +1 -0
  25. package/dist/main-browser.d.ts +9 -0
  26. package/dist/main-browser.js +26 -0
  27. package/dist/main-browser.js.map +1 -0
  28. package/dist/main.d.ts +58 -0
  29. package/dist/main.js +67 -0
  30. package/dist/main.js.map +1 -0
  31. package/dist/mockrtc-admin-plugin.d.ts +56 -0
  32. package/dist/mockrtc-admin-plugin.js +151 -0
  33. package/dist/mockrtc-admin-plugin.js.map +1 -0
  34. package/dist/mockrtc-admin-server.d.ts +7 -0
  35. package/dist/mockrtc-admin-server.js +18 -0
  36. package/dist/mockrtc-admin-server.js.map +1 -0
  37. package/dist/mockrtc-client.d.ts +12 -0
  38. package/dist/mockrtc-client.js +64 -0
  39. package/dist/mockrtc-client.js.map +1 -0
  40. package/dist/mockrtc-handler-builder.d.ts +15 -0
  41. package/dist/mockrtc-handler-builder.js +24 -0
  42. package/dist/mockrtc-handler-builder.js.map +1 -0
  43. package/dist/mockrtc-peer.d.ts +147 -0
  44. package/dist/mockrtc-peer.js +7 -0
  45. package/dist/mockrtc-peer.js.map +1 -0
  46. package/dist/mockrtc-remote-peer.d.ts +15 -0
  47. package/dist/mockrtc-remote-peer.js +234 -0
  48. package/dist/mockrtc-remote-peer.js.map +1 -0
  49. package/dist/mockrtc-server-peer.d.ts +29 -0
  50. package/dist/mockrtc-server-peer.js +145 -0
  51. package/dist/mockrtc-server-peer.js.map +1 -0
  52. package/dist/mockrtc-server.d.ts +14 -0
  53. package/dist/mockrtc-server.js +53 -0
  54. package/dist/mockrtc-server.js.map +1 -0
  55. package/dist/mockrtc.d.ts +25 -0
  56. package/dist/mockrtc.js +7 -0
  57. package/dist/mockrtc.js.map +1 -0
  58. package/dist/package.json +52 -0
  59. package/dist/server/mockrtc-admin-plugin.d.ts +17 -0
  60. package/dist/server/mockrtc-admin-plugin.js +163 -0
  61. package/dist/server/mockrtc-admin-plugin.js.map +1 -0
  62. package/dist/server/mockrtc-admin-server.d.ts +7 -0
  63. package/dist/server/mockrtc-admin-server.js +18 -0
  64. package/dist/server/mockrtc-admin-server.js.map +1 -0
  65. package/dist/server/mockrtc-server-peer.d.ts +24 -0
  66. package/dist/server/mockrtc-server-peer.js +141 -0
  67. package/dist/server/mockrtc-server-peer.js.map +1 -0
  68. package/dist/server/mockrtc-server.d.ts +14 -0
  69. package/dist/server/mockrtc-server.js +53 -0
  70. package/dist/server/mockrtc-server.js.map +1 -0
  71. package/dist/src/main.d.ts +1 -0
  72. package/dist/src/main.js +24 -0
  73. package/dist/src/main.js.map +1 -0
  74. package/dist/src/mockrtc-peer.d.ts +0 -0
  75. package/dist/src/mockrtc-peer.js +2 -0
  76. package/dist/src/mockrtc-peer.js.map +1 -0
  77. package/dist/src/mockrtc.d.ts +0 -0
  78. package/dist/src/mockrtc.js +65 -0
  79. package/dist/src/mockrtc.js.map +1 -0
  80. package/dist/webrtc/control-channel.d.ts +8 -0
  81. package/dist/webrtc/control-channel.js +11 -0
  82. package/dist/webrtc/control-channel.js.map +1 -0
  83. package/dist/webrtc/datachannel-stream.d.ts +25 -0
  84. package/dist/webrtc/datachannel-stream.js +86 -0
  85. package/dist/webrtc/datachannel-stream.js.map +1 -0
  86. package/dist/webrtc/mediatrack-stream.d.ts +29 -0
  87. package/dist/webrtc/mediatrack-stream.js +109 -0
  88. package/dist/webrtc/mediatrack-stream.js.map +1 -0
  89. package/dist/webrtc/mockrtc-connection.d.ts +14 -0
  90. package/dist/webrtc/mockrtc-connection.js +147 -0
  91. package/dist/webrtc/mockrtc-connection.js.map +1 -0
  92. package/dist/webrtc/peer-connection.d.ts +16 -0
  93. package/dist/webrtc/peer-connection.js +81 -0
  94. package/dist/webrtc/peer-connection.js.map +1 -0
  95. package/dist/webrtc/rtc-connection.d.ts +47 -0
  96. package/dist/webrtc/rtc-connection.js +370 -0
  97. package/dist/webrtc/rtc-connection.js.map +1 -0
  98. package/dist/webrtc-hooks.d.ts +30 -0
  99. package/dist/webrtc-hooks.js +224 -0
  100. package/dist/webrtc-hooks.js.map +1 -0
  101. package/karma.conf.ts +89 -0
  102. package/ngi-eu-footer.png +0 -0
  103. package/package.json +86 -0
  104. package/src/admin-bin.ts +57 -0
  105. package/src/client/mockrtc-client.ts +79 -0
  106. package/src/client/mockrtc-remote-peer.ts +286 -0
  107. package/src/handling/handler-builder.ts +215 -0
  108. package/src/handling/handler-step-definitions.ts +142 -0
  109. package/src/handling/handler-steps.ts +254 -0
  110. package/src/main-browser.ts +44 -0
  111. package/src/main.ts +109 -0
  112. package/src/mockrtc-peer.ts +176 -0
  113. package/src/mockrtc.ts +36 -0
  114. package/src/server/mockrtc-admin-plugin.ts +196 -0
  115. package/src/server/mockrtc-admin-server.ts +17 -0
  116. package/src/server/mockrtc-server-peer.ts +159 -0
  117. package/src/server/mockrtc-server.ts +53 -0
  118. package/src/webrtc/control-channel.ts +13 -0
  119. package/src/webrtc/datachannel-stream.ts +102 -0
  120. package/src/webrtc/mediatrack-stream.ts +135 -0
  121. package/src/webrtc/mockrtc-connection.ts +164 -0
  122. package/src/webrtc/rtc-connection.ts +420 -0
  123. package/src/webrtc-hooks.ts +245 -0
  124. package/test/integration/close-steps.spec.ts +39 -0
  125. package/test/integration/connection-setup.spec.ts +230 -0
  126. package/test/integration/echo-steps.spec.ts +88 -0
  127. package/test/integration/proxy.spec.ts +526 -0
  128. package/test/integration/send-steps.spec.ts +76 -0
  129. package/test/integration/smoke-test.spec.ts +100 -0
  130. package/test/integration/wait-steps.spec.ts +225 -0
  131. package/test/start-test-admin-server.ts +12 -0
  132. package/test/test-setup.ts +136 -0
  133. package/test/tsconfig.json +11 -0
  134. package/tsconfig.json +14 -0
  135. package/typedoc.json +19 -0
  136. package/wallaby.js +41 -0
package/karma.conf.ts ADDED
@@ -0,0 +1,89 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ const CONTINUOUS = process.env.CONTINUOUS_TEST === 'true';
7
+ const HEADFUL = process.env.HEADFUL_TEST === 'true';
8
+
9
+ import * as ChildProcess from 'child_process';
10
+
11
+ import { NodeModulesPolyfillPlugin } from '@esbuild-plugins/node-modules-polyfill';
12
+ import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill';
13
+
14
+ if (CONTINUOUS) {
15
+ const adminProc = ChildProcess.spawn(
16
+ "./node_modules/.bin/node-dev",
17
+ [
18
+ '--notify=false',
19
+ './test/start-test-admin-server.ts'
20
+ ],
21
+ { stdio: 'inherit' }
22
+ );
23
+
24
+ process.on('exit', () => adminProc.kill());
25
+
26
+ adminProc.on('exit', (code) => {
27
+ process.exit(code ?? 0); // Signalled = null = we killed it
28
+ });
29
+ } else {
30
+ require('./test/start-test-admin-server');
31
+ }
32
+
33
+ module.exports = function(config: any) {
34
+ config.set({
35
+ frameworks: ['mocha', 'chai'],
36
+ files: [
37
+ 'test/**/*.spec.ts'
38
+ ],
39
+ preprocessors: {
40
+ 'src/**/*.ts': ['esbuild'],
41
+ 'test/**/*.ts': ['esbuild']
42
+ },
43
+ esbuild: {
44
+ format: 'esm',
45
+ target: 'esnext',
46
+ plugins: [
47
+ NodeModulesPolyfillPlugin(),
48
+ NodeGlobalsPolyfillPlugin({
49
+ process: true,
50
+ buffer: true
51
+ })
52
+ ]
53
+ },
54
+ plugins: [
55
+ 'karma-chrome-launcher',
56
+ 'karma-chai',
57
+ 'karma-mocha',
58
+ 'karma-mocha-reporter',
59
+ 'karma-esbuild'
60
+ ],
61
+
62
+ reporters: ['mocha'],
63
+ mochaReporter: {
64
+ showDiff: true
65
+ },
66
+
67
+ port: 9876,
68
+ logLevel: config.LOG_INFO,
69
+
70
+ browsers: HEADFUL
71
+ ? ['ChromeWithFakeMedia']
72
+ : ['ChromeHeadlessWithFakeMedia'],
73
+
74
+ customLaunchers: {
75
+ ChromeHeadlessWithFakeMedia: {
76
+ base: 'ChromeHeadless',
77
+ flags: ['--use-fake-ui-for-media-stream', '--use-fake-device-for-media-stream']
78
+ },
79
+ ChromeWithFakeMedia: {
80
+ base: 'Chrome',
81
+ flags: ['--use-fake-ui-for-media-stream', '--use-fake-device-for-media-stream']
82
+ }
83
+ },
84
+
85
+ autoWatch: CONTINUOUS,
86
+ singleRun: !CONTINUOUS,
87
+ concurrency: Infinity
88
+ });
89
+ };
Binary file
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "mockrtc",
3
+ "version": "0.1.0",
4
+ "description": "Powerful friendly WebRTC mock peer & proxy",
5
+ "main": "dist/main.js",
6
+ "types": "dist/main.d.ts",
7
+ "browser": {
8
+ "dist/main.js": "./dist/main-browser.js",
9
+ "node-datachannel": false
10
+ },
11
+ "bin": {
12
+ "mockrtc": "./dist/admin-bin.js"
13
+ },
14
+ "sideEffects": [
15
+ "./test/**/*.spec.ts"
16
+ ],
17
+ "directories": {
18
+ "test": "test"
19
+ },
20
+ "scripts": {
21
+ "build": "npm run build:src && npm run build:doc",
22
+ "build:src": "tsc && chmod +x ./dist/admin-bin.js",
23
+ "build:doc": "typedoc src/main.ts",
24
+ "prepack": "npm run build",
25
+ "test": "karma start",
26
+ "test:dev": "CONTINUOUS_TEST=true npm run test",
27
+ "test:dev:debug": "HEADFUL_TEST=true CONTINUOUS_TEST=true npm run test"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/httptoolkit/mockrtc.git"
32
+ },
33
+ "keywords": [
34
+ "webrtc",
35
+ "rtc",
36
+ "mock",
37
+ "test",
38
+ "proxy"
39
+ ],
40
+ "author": "Tim Perry <tim@httptoolkit.tech>",
41
+ "license": "Apache-2.0",
42
+ "bugs": {
43
+ "url": "https://github.com/httptoolkit/mockrtc/issues"
44
+ },
45
+ "homepage": "https://github.com/httptoolkit/mockrtc#readme",
46
+ "engines": {
47
+ "node": ">=14.17.0"
48
+ },
49
+ "devDependencies": {
50
+ "@esbuild-plugins/node-globals-polyfill": "^0.1.1",
51
+ "@esbuild-plugins/node-modules-polyfill": "^0.1.4",
52
+ "@types/chai": "4.3.0",
53
+ "@types/dom-mediacapture-transform": "0.1.2",
54
+ "@types/dom-webcodecs": "0.1.3",
55
+ "@types/mocha": "^9.1.0",
56
+ "buffer": "^6.0.3",
57
+ "chai": "^4.3.6",
58
+ "esbuild": "^0.14.23",
59
+ "karma": "^6.3.16",
60
+ "karma-chai": "^0.1.0",
61
+ "karma-chrome-launcher": "^3.1.0",
62
+ "karma-esbuild": "^2.2.2",
63
+ "karma-mocha": "^2.0.1",
64
+ "karma-mocha-reporter": "^2.2.5",
65
+ "mocha": "^9.2.0",
66
+ "node-dev": "^7.1.0",
67
+ "rollup-plugin-node-polyfills": "^0.2.1",
68
+ "ts-node": "^10.5.0",
69
+ "typedoc": "^0.23.0-beta.1",
70
+ "typescript": "^4.6.4",
71
+ "util": "^0.12.4"
72
+ },
73
+ "dependencies": {
74
+ "@types/sdp-transform": "^2.4.5",
75
+ "graphql": "^15.8.0",
76
+ "graphql-tag": "^2.12.6",
77
+ "mockttp": "^3.0.0",
78
+ "node-datachannel": "^0.3.0",
79
+ "sdp-transform": "^2.14.1"
80
+ },
81
+ "overrides": {
82
+ "ts-node": {
83
+ "typescript": "*"
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import childProcess = require('child_process');
8
+ import MockRTC = require('./main');
9
+
10
+ handleArgs(process.argv).catch((e) => {
11
+ console.error(e);
12
+ process.exit(1);
13
+ });
14
+
15
+ async function handleArgs(args: string[]) {
16
+ const remainingArgs = args.slice(2);
17
+ let nextArg = remainingArgs.shift();
18
+ while (nextArg) {
19
+ if (nextArg === '-c') {
20
+ await runCommandWithServer(remainingArgs.join(' '));
21
+ return;
22
+ } else {
23
+ break;
24
+ }
25
+ }
26
+
27
+ console.log("Usage: mockrtc -c <test command>");
28
+ process.exit(1);
29
+ }
30
+
31
+ async function runCommandWithServer(command: string) {
32
+ const server = MockRTC.getAdminServer();
33
+ await server.start();
34
+
35
+ let realProcess = childProcess.spawn(command, [], {
36
+ shell: true,
37
+ stdio: 'inherit'
38
+ });
39
+
40
+ realProcess.on('error', (error) => {
41
+ server.stop().then(function () {
42
+ console.error(error);
43
+ process.exit(1);
44
+ });
45
+ });
46
+
47
+ realProcess.on('exit', (code, signal) => {
48
+ server.stop().then(function () {
49
+ if (code == null) {
50
+ console.error('Executed process exited due to signal: ' + signal);
51
+ process.exit(1);
52
+ } else {
53
+ process.exit(code);
54
+ }
55
+ });
56
+ });
57
+ }
@@ -0,0 +1,79 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import gql from 'graphql-tag';
7
+
8
+ // Long-term, it'd be great to use the 'official' export path of mockttp/pluggable-admin, but
9
+ // if we do so, then TypeScript <4.7 doesn't understand it here or downstream, so we get errors.
10
+ // We don't want to use the main-exported version to avoid bundling all of Mockttp in browsers.
11
+ // For now we have to use the direct import. We can update once TS 4.7 is widely used.
12
+ import * as BrowserPluggableAdmin from 'mockttp/dist/pluggable-admin-api/pluggable-admin.browser';
13
+ import type { PluggableAdmin } from 'mockttp';
14
+
15
+ import { MockRTC, MockRTCOptions, MockRTCPeerBuilder } from "../mockrtc";
16
+
17
+ import type { MockRTCAdminPlugin } from "../server/mockrtc-admin-plugin";
18
+ import type { MockRTCPeer } from '../mockrtc-peer';
19
+ import { MockRTCRemotePeer } from './mockrtc-remote-peer';
20
+ import { MockRTCHandlerBuilder } from '../handling/handler-builder';
21
+ import { HandlerStepDefinition } from '../handling/handler-step-definitions';
22
+
23
+ export type MockRTCClientOptions =
24
+ PluggableAdmin.AdminClientOptions &
25
+ MockRTCOptions;
26
+
27
+ export class MockRTCClient implements MockRTC {
28
+
29
+ private adminClient: PluggableAdmin.AdminClient<{ webrtc: MockRTCAdminPlugin }>;
30
+
31
+ constructor(
32
+ private options: MockRTCClientOptions = {}
33
+ ) {
34
+ this.adminClient = new BrowserPluggableAdmin.AdminClient(options);
35
+ }
36
+
37
+ buildPeer(): MockRTCPeerBuilder {
38
+ return new MockRTCHandlerBuilder(this.buildPeerFromData);
39
+ }
40
+
41
+ private buildPeerFromData = async (handlerSteps: HandlerStepDefinition[]): Promise<MockRTCPeer> => {
42
+ const { adminStream } = this.adminClient;
43
+
44
+ const peerData = await this.adminClient.sendQuery<
45
+ { createPeer: { peerId: string } },
46
+ { peerId: string }
47
+ >({
48
+ query: gql`
49
+ mutation CreatePeer($peerData: RTCHandlerData!) {
50
+ createPeer(data: $peerData) {
51
+ peerId
52
+ }
53
+ }
54
+ `,
55
+ variables: {
56
+ peerData: {
57
+ steps: handlerSteps.map(step =>
58
+ BrowserPluggableAdmin.Serialization.serialize(step, adminStream)
59
+ )
60
+ }
61
+ },
62
+ transformResponse: ({ createPeer }) => createPeer
63
+ });
64
+
65
+ const { peerId } = peerData;
66
+
67
+ return new MockRTCRemotePeer(peerId, this.adminClient);
68
+ }
69
+
70
+ async start(): Promise<void> {
71
+ await this.adminClient.start({
72
+ webrtc: this.options
73
+ });
74
+ }
75
+
76
+ async stop(): Promise<void> {
77
+ await this.adminClient.stop();
78
+ }
79
+ }
@@ -0,0 +1,286 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import { gql } from 'graphql-tag';
7
+ import * as PluggableAdmin from 'mockttp/dist/pluggable-admin-api/pluggable-admin.browser';
8
+
9
+ import {
10
+ MockRTCPeer,
11
+ MockRTCOfferParams,
12
+ MockRTCExternalOfferParams,
13
+ MockRTCExternalAnswerParams,
14
+ MockRTCAnswerParams,
15
+ MockRTCSession,
16
+ OfferOptions,
17
+ AnswerOptions
18
+ } from "../mockrtc-peer";
19
+ import type { SessionData } from '../server/mockrtc-admin-plugin';
20
+
21
+ export class MockRTCRemotePeer implements MockRTCPeer {
22
+
23
+ constructor(
24
+ readonly peerId: string,
25
+ private adminClient: PluggableAdmin.AdminClient<{}>
26
+ ) {}
27
+
28
+ createOffer(options?: OfferOptions): Promise<MockRTCOfferParams> {
29
+ return this.adminClient.sendQuery<
30
+ { createOffer: SessionData },
31
+ MockRTCOfferParams
32
+ >({
33
+ query: gql`
34
+ mutation GetPeerRTCOffer($peerId: ID!, $options: Raw) {
35
+ createOffer(peerId: $peerId, options: $options) {
36
+ id
37
+ description {
38
+ type
39
+ sdp
40
+ }
41
+ }
42
+ }
43
+ `,
44
+ variables: { peerId: this.peerId, options },
45
+ transformResponse: ({ createOffer }) => {
46
+ const session = this.getSession(createOffer.id);
47
+ return {
48
+ offer: createOffer.description,
49
+ session,
50
+ setAnswer: session.completeOffer.bind(session)
51
+ };
52
+ }
53
+ });
54
+ }
55
+
56
+ createExternalOffer(options?: OfferOptions): Promise<MockRTCExternalOfferParams> {
57
+ return this.adminClient.sendQuery<
58
+ { createExternalOffer: SessionData },
59
+ MockRTCExternalOfferParams
60
+ >({
61
+ query: gql`
62
+ mutation GetPeerRTCExternalOffer($peerId: ID!, $options: Raw) {
63
+ createExternalOffer(peerId: $peerId, options: $options) {
64
+ id
65
+ description {
66
+ type
67
+ sdp
68
+ }
69
+ }
70
+ }
71
+ `,
72
+ variables: { peerId: this.peerId, options },
73
+ transformResponse: ({ createExternalOffer }) => {
74
+ const session = this.getSession(createExternalOffer.id);
75
+ return {
76
+ id: createExternalOffer.id,
77
+ offer: createExternalOffer.description,
78
+ session,
79
+ setAnswer: session.completeOffer.bind(session)
80
+ };
81
+ }
82
+ });
83
+ }
84
+
85
+ async answerOffer(
86
+ offer: RTCSessionDescriptionInit,
87
+ options?: AnswerOptions
88
+ ): Promise<MockRTCAnswerParams> {
89
+ return this.adminClient.sendQuery<
90
+ { answerOffer: SessionData },
91
+ MockRTCAnswerParams
92
+ >({
93
+ query: gql`
94
+ mutation GetPeerRTCAnswer(
95
+ $peerId: ID!,
96
+ $offer: SessionDescriptionInput!,
97
+ $options: Raw
98
+ ) {
99
+ answerOffer(peerId: $peerId, offer: $offer, options: $options) {
100
+ id
101
+ description {
102
+ type
103
+ sdp
104
+ }
105
+ }
106
+ }
107
+ `,
108
+ variables: { peerId: this.peerId, offer, options },
109
+ transformResponse: ({ answerOffer }) => ({
110
+ answer: answerOffer.description,
111
+ session: this.getSession(answerOffer.id)
112
+ })
113
+ });
114
+ }
115
+
116
+ async answerExternalOffer(
117
+ offer: RTCSessionDescriptionInit,
118
+ options?: AnswerOptions
119
+ ): Promise<MockRTCExternalAnswerParams> {
120
+ return this.adminClient.sendQuery<
121
+ { answerExternalOffer: SessionData },
122
+ MockRTCExternalAnswerParams
123
+ >({
124
+ query: gql`
125
+ mutation GetPeerRTCExternalAnswer(
126
+ $peerId: ID!,
127
+ $offer: SessionDescriptionInput!,
128
+ $options: Raw
129
+ ) {
130
+ answerExternalOffer(peerId: $peerId, offer: $offer, options: $options) {
131
+ id
132
+ description {
133
+ type
134
+ sdp
135
+ }
136
+ }
137
+ }
138
+ `,
139
+ variables: { peerId: this.peerId, offer, options },
140
+ transformResponse: ({ answerExternalOffer }) => {
141
+ const session = this.getSession(answerExternalOffer.id);
142
+ return {
143
+ id: answerExternalOffer.id,
144
+ answer: answerExternalOffer.description,
145
+ session
146
+ }
147
+ }
148
+ });
149
+ }
150
+
151
+ getSession(sessionId: string): MockRTCSession {
152
+ return new RemoteSessionApi(this.adminClient, this.peerId, sessionId);
153
+ }
154
+
155
+ getAllMessages() {
156
+ return this.adminClient.sendQuery<
157
+ { getSeenMessages: Array<string | { type: 'buffer', value: string }> },
158
+ Array<string | Buffer>
159
+ >({
160
+ query: gql`
161
+ query GetPeerSeenMessages($peerId: ID!) {
162
+ getSeenMessages(peerId: $peerId)
163
+ }
164
+ `,
165
+ variables: { peerId: this.peerId },
166
+ transformResponse: ({ getSeenMessages }) => {
167
+ return getSeenMessages.map((message) => {
168
+ if (typeof message === 'string') {
169
+ return message;
170
+ } else if (message.type === 'buffer') {
171
+ return Buffer.from(message.value, 'base64');
172
+ } else {
173
+ throw new Error(`Unparseable message data: ${JSON.stringify(message)}`);
174
+ }
175
+ });
176
+ }
177
+ });
178
+ }
179
+
180
+ getMessagesOnChannel(channelName: string): Promise<Array<string | Buffer>> {
181
+ return this.adminClient.sendQuery<
182
+ { getSeenMessages: Array<string | { type: 'buffer', value: string }> },
183
+ Array<string | Buffer>
184
+ >({
185
+ query: gql`
186
+ query GetPeerSeenMessages($peerId: ID!, $channelName: String) {
187
+ getSeenMessages(peerId: $peerId, channelName: $channelName)
188
+ }
189
+ `,
190
+ variables: { peerId: this.peerId, channelName },
191
+ transformResponse: ({ getSeenMessages }) => {
192
+ return getSeenMessages.map((message) => {
193
+ if (typeof message === 'string') {
194
+ return message;
195
+ } else if (message.type === 'buffer') {
196
+ return Buffer.from(message.value, 'base64');
197
+ } else {
198
+ throw new Error(`Unparseable message data: ${JSON.stringify(message)}`);
199
+ }
200
+ });
201
+ }
202
+ });
203
+ }
204
+
205
+ }
206
+
207
+ class RemoteSessionApi implements MockRTCSession {
208
+ constructor(
209
+ private adminClient: PluggableAdmin.AdminClient<{}>,
210
+ private peerId: string,
211
+ public readonly sessionId: string
212
+ ) {}
213
+
214
+ createOffer(options?: OfferOptions): Promise<RTCSessionDescriptionInit> {
215
+ return this.adminClient.sendQuery<
216
+ { createOffer: SessionData },
217
+ RTCSessionDescriptionInit
218
+ >({
219
+ query: gql`
220
+ mutation GetPeerRTCSessionOffer($peerId: ID!, $sessionId: ID!, $options: Raw) {
221
+ createOffer(peerId: $peerId, sessionId: $sessionId, options: $options) {
222
+ description {
223
+ type
224
+ sdp
225
+ }
226
+ }
227
+ }
228
+ `,
229
+ variables: { peerId: this.peerId, sessionId: this.sessionId, options },
230
+ transformResponse: ({ createOffer }) => createOffer.description
231
+ });
232
+ }
233
+
234
+ completeOffer(answer: RTCSessionDescriptionInit): Promise<void> {
235
+ return this.adminClient.sendQuery<void>({
236
+ query: gql`
237
+ mutation CompletePeerRTCOffer(
238
+ $peerId: ID!,
239
+ $sessionId: ID!,
240
+ $answer: SessionDescriptionInput!
241
+ ) {
242
+ completeOffer(peerId: $peerId, sessionId: $sessionId, answer: $answer)
243
+ }
244
+ `,
245
+ variables: {
246
+ peerId: this.peerId,
247
+ sessionId: this.sessionId,
248
+ answer: answer
249
+ }
250
+ });
251
+ }
252
+
253
+ answerOffer(
254
+ offer: RTCSessionDescriptionInit,
255
+ options?: AnswerOptions
256
+ ): Promise<RTCSessionDescriptionInit> {
257
+ return this.adminClient.sendQuery<
258
+ { answerOffer: SessionData },
259
+ RTCSessionDescriptionInit
260
+ >({
261
+ query: gql`
262
+ mutation GetPeerRTCAnswer(
263
+ $peerId: ID!,
264
+ $sessionId: ID!,
265
+ $offer: SessionDescriptionInput!,
266
+ $options: Raw
267
+ ) {
268
+ answerOffer(peerId: $peerId, sessionId: $sessionId, offer: $offer, options: $options) {
269
+ description {
270
+ type
271
+ sdp
272
+ }
273
+ }
274
+ }
275
+ `,
276
+ variables: {
277
+ peerId: this.peerId,
278
+ sessionId: this.sessionId,
279
+ offer,
280
+ options
281
+ },
282
+ transformResponse: ({ answerOffer }) => answerOffer.description
283
+ });
284
+ }
285
+
286
+ }