diff --git a/README.md b/README.md index 0aed177..011e388 100644 --- a/README.md +++ b/README.md @@ -84,20 +84,20 @@ If you have your own server, you can attach PeerServer. ## Config / CLI options You can provide config object to `PeerServer` function or specify options for `peerjs` CLI. -| CLI option | JS option | Description | Required | Default | -| -------- | ------- | ------------- | :------: | :---------: | -| `--port, -p` | `port` | Port to listen (number) | **Yes** | | -| `--key, -k` | `key` | Connection key (string). Client must provide it to call API methods | No | `"peerjs"` | -| `--path` | `path` | Path (string). The server responds for requests to the root URL + path. **E.g.** Set the `path` to `/myapp` and run server on 9000 port via `peerjs --port 9000 --path /myapp` Then open http://127.0.0.1:9000/myapp - you should see a JSON reponse. | No | `"/"` | -| `--proxied` | `proxied` | Set `true` if PeerServer stays behind a reverse proxy (boolean) | No | `false` | -| `--expire_timeout, -t` | `expire_timeout` | The amount of time after which a message sent will expire, the sender will then receive a `EXPIRE` message (milliseconds). | No | `5000` | -| `--alive_timeout` | `alive_timeout` | Timeout for broken connection (milliseconds). If the server doesn't receive any data from client (includes `pong` messages), the client's connection will be destroyed. | No | `60000` | -| `--concurrent_limit, -c` | `concurrent_limit` | Maximum number of clients' connections to WebSocket server (number) | No | `5000` | -| `--sslkey` | `sslkey` | Path to SSL key (string) | No | | -| `--sslcert` | `sslcert` | Path to SSL certificate (string) | No | | -| `--allow_discovery` | `allow_discovery` | Allow to use GET `/peers` http API method to get an array of ids of all connected clients (boolean) | No | | -| | `generateClientId` | A function which generate random client IDs when calling `/id` API method (`() => string`) | No | `uuid/v4` | - +| CLI option | JS option | Description | Required | Default | +|--------------------------|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------:|:----------:| +| `--port, -p` | `port` | Port to listen (number) | **Yes** | | +| `--key, -k` | `key` | Connection key (string). Client must provide it to call API methods | No | `"peerjs"` | +| `--path` | `path` | Path (string). The server responds for requests to the root URL + path. **E.g.** Set the `path` to `/myapp` and run server on 9000 port via `peerjs --port 9000 --path /myapp` Then open http://127.0.0.1:9000/myapp - you should see a JSON reponse. | No | `"/"` | +| `--proxied` | `proxied` | Set `true` if PeerServer stays behind a reverse proxy (boolean) | No | `false` | +| `--expire_timeout, -t` | `expire_timeout` | The amount of time after which a message sent will expire, the sender will then receive a `EXPIRE` message (milliseconds). | No | `5000` | +| `--alive_timeout` | `alive_timeout` | Timeout for broken connection (milliseconds). If the server doesn't receive any data from client (includes `pong` messages), the client's connection will be destroyed. | No | `60000` | +| `--concurrent_limit, -c` | `concurrent_limit` | Maximum number of clients' connections to WebSocket server (number) | No | `5000` | +| `--sslkey` | `sslkey` | Path to SSL key (string) | No | | +| `--sslcert` | `sslcert` | Path to SSL certificate (string) | No | | +| `--allow_discovery` | `allow_discovery` | Allow to use GET `/peers` http API method to get an array of ids of all connected clients (boolean) | No | | +| `--cors` | `corsOptions` | The CORS origins that can access this server | +| | `generateClientId` | A function which generate random client IDs when calling `/id` API method (`() => string`) | No | `uuid/v4` | ## Using HTTPS Simply pass in PEM-encoded certificate and key. diff --git a/__test__/peerjs.spec.ts b/__test__/peerjs.spec.ts index 326e7f5..f4c617a 100644 --- a/__test__/peerjs.spec.ts +++ b/__test__/peerjs.spec.ts @@ -1,57 +1,91 @@ -import { describe, expect, it } from "@jest/globals"; +import {describe, expect, it} from "@jest/globals"; import http from 'http'; import expectedJson from '../app.json'; -import { spawn } from 'child_process'; -import path from 'path'; +import fetch from "node-fetch"; +import * as crypto from "crypto"; +import {startServer} from "./utils"; const PORT = '9000'; async function makeRequest() { - return new Promise((resolve, reject) => { - http.get(`http://localhost:${PORT}/`, resp => { - let data = ''; + return new Promise((resolve, reject) => { + http.get(`http://localhost:${PORT}/`, resp => { + let data = ''; - resp.on('data', chunk => { - data += chunk; - }); + resp.on('data', chunk => { + data += chunk; + }); - resp.on('end', () => { - resolve(JSON.parse(data)); - }); + resp.on('end', () => { + resolve(JSON.parse(data)); + }); - }).on("error", err => { - console.log("Error: " + err.message); - reject(err); + }).on("error", err => { + console.log("Error: " + err.message); + reject(err); + }); }); - }); } describe('Check bin/peerjs', () => { - it('should return content of app.json file', async () => { - expect.assertions(1); - let resolver: () => void; - let rejecter: (err: unknown) => void; - const promise = new Promise((resolve, reject) => { - resolver = resolve; - rejecter = reject; + it('should return content of app.json file', async () => { + expect.assertions(1); + + const ls = await startServer() + try { + const resp = await makeRequest(); + expect(resp).toEqual(expectedJson); + } finally { + ls.kill(); + } + }); - const ls = spawn('node', [path.join(__dirname, '../', 'dist/bin/peerjs.js'), '--port', PORT]); - ls.stdout.on('data', async (data: string) => { - if (!data.includes('Started')) return; + it('should reflect the origin header in CORS by default', async () => { + expect.assertions(1); - try { - const resp = await makeRequest(); - expect(resp).toEqual(expectedJson); - resolver(); - } catch (error) { - rejecter(error); - } finally { - ls.kill('SIGKILL'); - } + const ls = await startServer() + const origin = crypto.randomUUID(); + try { + const res = await fetch(`http://localhost:${PORT}/peerjs/id`, { + headers: { + Origin: origin + } + }) + expect(res.headers.get("access-control-allow-origin")).toBe(origin) + } finally { + ls.kill() + } }); + it('should respect the CORS parameters', async () => { + expect.assertions(3); - return promise; - }); + const origin1 = crypto.randomUUID(); + const origin2 = crypto.randomUUID(); + const origin3 = crypto.randomUUID(); + const ls = await startServer(["--cors", origin1, "--cors", origin2]) + try { + const res1 = await fetch(`http://localhost:${PORT}/peerjs/id`, { + headers: { + Origin: origin1 + } + }) + expect(res1.headers.get("access-control-allow-origin")).toBe(origin1) + const res2 = await fetch(`http://localhost:${PORT}/peerjs/id`, { + headers: { + Origin: origin2 + } + }) + expect(res2.headers.get("access-control-allow-origin")).toBe(origin2) + const res3 = await fetch(`http://localhost:${PORT}/peerjs/id`, { + headers: { + Origin: origin3 + } + }) + expect(res3.headers.get("access-control-allow-origin")).toBe(null) + } finally { + ls.kill() + } + }); }); diff --git a/__test__/utils.ts b/__test__/utils.ts index cbbd648..940d7f8 100644 --- a/__test__/utils.ts +++ b/__test__/utils.ts @@ -1 +1,15 @@ +import {ChildProcessWithoutNullStreams, spawn} from "child_process"; +import path from "path"; + export const wait = (ms: number): Promise => new Promise(resolve => setTimeout(resolve, ms)); + +export const startServer = (params: string[] = []) => { + return new Promise((resolve, reject)=> { + const ls = spawn('node', [path.join(__dirname, '../', 'dist/bin/peerjs.js'), '--port', "9000", ...params]); + ls.stdout.once("data", ()=> resolve(ls)) + ls.stderr.once("data", ()=>{ + ls.kill() + reject() + }) + }) +} diff --git a/bin/peerjs.ts b/bin/peerjs.ts index d2c5447..21a0842 100644 --- a/bin/peerjs.ts +++ b/bin/peerjs.ts @@ -8,6 +8,7 @@ import yargs from "yargs"; import { hideBin } from 'yargs/helpers' import { PeerServer} from "../src"; import type { AddressInfo } from "node:net"; +import type {CorsOptions} from "cors"; const y = yargs(hideBin(process.argv)); @@ -73,18 +74,28 @@ const opts = y demandOption: false, describe: "allow discovery of peers", }, - proxied: { - type: "boolean", - demandOption: false, - describe: "Set true if PeerServer stays behind a reverse proxy", - default: false, - }, + proxied: { + type: "boolean", + demandOption: false, + describe: "Set true if PeerServer stays behind a reverse proxy", + default: false, + }, + cors: { + type: "string", + array: true, + describe: "Set the list of CORS origins", + }, }) .boolean("allow_discovery").parseSync(); if(!opts.port){ opts.port= parseInt(process.env["PORT"] as string) } +if(opts.cors){ + opts["corsOptions"] = { + origin: opts.cors + } satisfies CorsOptions; +} process.on("uncaughtException", function (e) { console.error("Error: " + e); }); diff --git a/jest.config.js b/jest.config.js index b20fd89..60d0514 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,9 +1,13 @@ /** @type {import('jest').Config} */ const config = { - transform: { - "^.+\\.(t|j)sx?$": "@swc/jest", - }, - collectCoverageFrom: ["./src/**"] + testEnvironment: "node", + transform: { + "^.+\\.(t|j)sx?$": "@swc/jest", + }, + transformIgnorePatterns: [ + // "node_modules" + ], + collectCoverageFrom: ["./src/**"] }; export default config; diff --git a/package-lock.json b/package-lock.json index c31fc7d..3f6b932 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@types/ws": "^7.2.3 || ^8.0.0", "cors": "^2.8.5", "express": "^4.17.1", + "node-fetch": "^3.3.0", "ws": "^7.2.3 || ^8.0.0", "yargs": "^17.6.2" }, @@ -1799,6 +1800,26 @@ "node": ">= 14" } }, + "node_modules/@octokit/request/node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/@octokit/rest": { "version": "19.0.7", "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.7.tgz", @@ -5028,6 +5049,14 @@ "node": ">=8.0.0" } }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, "node_modules/dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -5949,6 +5978,28 @@ "bser": "2.1.1" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/figures": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", @@ -6093,6 +6144,17 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -8758,6 +8820,24 @@ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-emoji": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", @@ -8768,23 +8848,20 @@ } }, "node_modules/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dev": true, + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", + "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", "dependencies": { - "whatwg-url": "^5.0.0" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": "4.x || >=6.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "node_modules/node-gyp-build": { @@ -13980,6 +14057,14 @@ "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", "dev": true }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -15496,6 +15581,17 @@ "is-plain-object": "^5.0.0", "node-fetch": "^2.6.7", "universal-user-agent": "^6.0.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + } } }, "@octokit/request-error": { @@ -17778,6 +17874,11 @@ "css-tree": "^1.1.2" } }, + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" + }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -18460,6 +18561,15 @@ "bser": "2.1.1" } }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, "figures": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", @@ -18566,6 +18676,14 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "requires": { + "fetch-blob": "^3.1.2" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -20527,6 +20645,11 @@ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + }, "node-emoji": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", @@ -20537,12 +20660,13 @@ } }, "node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dev": true, + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", + "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", "requires": { - "whatwg-url": "^5.0.0" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" } }, "node-gyp-build": { @@ -24254,6 +24378,11 @@ "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", "dev": true }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index 644c886..87443c0 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "@types/ws": "^7.2.3 || ^8.0.0", "cors": "^2.8.5", "express": "^4.17.1", + "node-fetch": "^3.3.0", "ws": "^7.2.3 || ^8.0.0", "yargs": "^17.6.2" }, diff --git a/src/api/index.ts b/src/api/index.ts index 2e3d2f5..7e5d192 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,17 +1,18 @@ -import cors from "cors"; +import cors, {CorsOptions} from "cors"; import express from "express"; import publicContent from "../../app.json"; import PublicApi from "./v1/public"; import type {IConfig} from "../config"; import type {IRealm} from "../models/realm"; -export const Api = ({ config, realm }: { +export const Api = ({ config, realm, corsOptions }: { config: IConfig; realm: IRealm; + corsOptions: CorsOptions; }): express.Router => { const app = express.Router(); - app.use(cors()); + app.use(cors(corsOptions)); app.get("/", (_, res) => { res.send(publicContent); diff --git a/src/config/index.ts b/src/config/index.ts index b859bcd..6415d18 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,4 +1,5 @@ import type {WebSocketServer, ServerOptions} from 'ws'; +import type {CorsOptions} from "cors"; export interface IConfig { readonly host: string; @@ -17,6 +18,7 @@ export interface IConfig { }; readonly generateClientId?: () => string; readonly createWebSocketServer?: (options: ServerOptions) => WebSocketServer; + readonly corsOptions : CorsOptions; } const defaultConfig: IConfig = { @@ -30,6 +32,7 @@ const defaultConfig: IConfig = { allow_discovery: false, proxied: false, cleanup_out_msgs: 1000, + corsOptions: {origin: true}, }; export default defaultConfig; diff --git a/src/instance.ts b/src/instance.ts index 6e46efc..cd41871 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -31,7 +31,7 @@ export const createInstance = ({ app, server, options }: { const realm: IRealm = new Realm(); const messageHandler = new MessageHandler(realm); - const api = Api({ config, realm }); + const api = Api({ config, realm , corsOptions: options.corsOptions }); const messagesExpire: IMessagesExpire = new MessagesExpire({ realm, config, messageHandler }); const checkBrokenConnections = new CheckBrokenConnections({ realm,