diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index eb9cdb0..880d227 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -12,12 +12,12 @@ jobs: strategy: matrix: - node-version: [14.x, 16.x, 18.x, 20.x] + node-version: [16.x, 18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use NodeJS ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/README.md b/README.md index 3a7a61d..4144bb7 100644 --- a/README.md +++ b/README.md @@ -4,45 +4,26 @@ ### CometD NodeJS Client -This project implements adapter code that allows the [CometD JavaScript Client](https://github.com/cometd/cometd-javascript) to run in a NodeJS environment. +This project implements ES6 adapter code that allows the [CometD JavaScript Client](https://github.com/cometd/cometd-javascript) to run in a NodeJS environment. -The adapter code exports an implementation of `XMLHttpRequest` so that the CometD JavaScript Client works in NodeJS as it does within a browser environment. +The adapter code exports an implementation of `XMLHttpRequest` and `WebSocket` so that the CometD JavaScript Client works in NodeJS as it does within a browser environment. WebSocket is supported via the [`ws`](https://www.npmjs.com/package/ws) package. ### NPM Installation -Firstly, you need to install the CometD NodeJS Client: +Install the CometD NodeJS Client: -``` +```js npm install cometd-nodejs-client ``` -The CometD NodeJS Client does not depend on the CometD JavaScript Client; you need the CometD JavaScript Client to develop your applications. - -Therefore, you need to install the CometD JavaScript Client, version 3.1.2 or greater: - -``` -npm install cometd -``` - -### Usage (CommonJS) - -```javascript -// Run the adapter code that implements XMLHttpRequest. -require('cometd-nodejs-client').adapt(); - -// Your normal CometD client application here. -var lib = require('cometd'); -var cometd = new lib.CometD(); -... -``` +### Usage (ES6) -### Usage (ES Modules) +```js +import { adapt } from "cometd-nodejs-client"; +import { CometD } from "cometd"; -```javascript -import { CometD } from 'cometd'; -import { adapt } from 'cometd-nodejs-client'; // Shim XMLHTTPRequest for Node.js (required by CometD). adapt(); diff --git a/RELEASE.md b/RELEASE.md index c95ecca..7ba8b25 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,5 +1,6 @@ ### Release Instructions (for project committers) +* Run the tests: `npm test` * Update the `version` field in `package.json` to the version you want to cut. * Commit: `git commit -s -S -m "Release ."` * Create the git tag: `git tag -a -s -m "Release ." ` diff --git a/cometd-nodejs-client.d.ts b/cometd-nodejs-client.d.ts index 65c0f68..122ef31 100644 --- a/cometd-nodejs-client.d.ts +++ b/cometd-nodejs-client.d.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + export interface HttpProxy { uri?: string; includes?: string[]; @@ -25,7 +26,7 @@ export interface Cookies { } export interface Options { - logLevel?: 'debug' | 'info'; + logLevel?: "debug" | "info"; httpProxy?: HttpProxy; cookies?: Cookies; } diff --git a/cometd-nodejs-client.js b/cometd-nodejs-client.js index 1a08df0..bde1322 100644 --- a/cometd-nodejs-client.js +++ b/cometd-nodejs-client.js @@ -13,290 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -module.exports = { - adapt: options => { - const url = require('url'); - const httpc = require('http'); - const https = require('https'); - const httpcProxyAgent = require('http-proxy-agent'); - const httpsProxyAgent = require('https-proxy-agent'); - const ws = require('ws'); +import {XMLHttpRequest} from "./src/XMLHttpRequest.js"; +import * as ws from "ws"; - let window = global['window']; - if (!window) { - window = global['window'] = {}; - } - - window.setTimeout = setTimeout; - window.clearTimeout = clearTimeout; - - window.console = console; - window.console.debug = window.console.log; - - // Fields shared by all XMLHttpRequest instances. - const _agentOptions = { - keepAlive: true - }; - const _agentc = new httpc.Agent(_agentOptions); - const _agents = new https.Agent(_agentOptions); - - const _globalCookies = {}; - - const _logLevel = options && options.logLevel || 'info'; - - function _debug() { - if (_logLevel === 'debug') { - console.log.apply(this, Array.from(arguments)); - } - } +export function adapt(options) { + let window = global["window"]; + if (!window) { + window = global["window"] = {}; + } - function _secure(uri) { - return /^https/i.test(uri.protocol); - } + window.setTimeout = setTimeout; + window.clearTimeout = clearTimeout; - function _storeServerCookie(uri, header, callback) { - if (options && options.cookies && options.cookies.storeCookie) { - options.cookies.storeCookie(uri, header, callback); - } else { - const host = uri.hostname; - let jar = _globalCookies[host]; - if (jar === undefined) { - _globalCookies[host] = jar = {}; - } - const parts = header.split(';'); - // Ignore domain, path, expiration, etc. - const nameValue = parts[0].trim(); - const equal = nameValue.indexOf('='); - if (equal > 0) { - const name = nameValue.substring(0, equal); - jar[name] = nameValue; - } - callback(); - } - } + window.console = console; + window.console.debug = window.console.log; - function _retrieveServerCookies(context, uri, callback) { - if (options && options.cookies && options.cookies.retrieveCookies) { - options.cookies.retrieveCookies(context, uri, callback); - } else { - let globalCookies = context && context.cookieStore; - if (!globalCookies) { - globalCookies = _globalCookies; - } - let cookies = []; - const jar = globalCookies[uri.hostname]; - if (jar) { - for (let name in jar) { - if (jar.hasOwnProperty(name)) { - cookies.push(jar[name]); - } - } - } - callback(null, cookies); - } - } + options = options || {}; + options.globalCookies = {}; - function _asyncForEach(array, index, operation, callback) { - while (index < array.length) { - let complete = false; - let proceed = false; - operation(array[index], () => { - complete = true; - if (proceed) { - ++index; - _asyncForEach(array, index, operation, callback); - } - }); - if (complete) { - ++index; - } else { - proceed = true; - break; - } - } - if (index === array.length) { - callback(); - } + window.XMLHttpRequest = class extends XMLHttpRequest { + constructor() { + super(options); } + }; - // Bare minimum XMLHttpRequest implementation that works with CometD. - window.XMLHttpRequest = function() { - const _localCookies = {}; - let _config; - let _request; - - function _storeCookie(value) { - const host = _config.hostname; - let jar = _localCookies[host]; - if (jar === undefined) { - _localCookies[host] = jar = {}; - } - const cookies = value.split(';'); - for (let i = 0; i < cookies.length; ++i) { - const cookie = cookies[i].trim(); - const equal = cookie.indexOf('='); - if (equal > 0) { - jar[cookie.substring(0, equal)] = cookie; - } - } - } - - function _retrieveCookies() { - const cookies = []; - const jar = _localCookies[_config.hostname]; - if (jar) { - for (let name in jar) { - if (jar.hasOwnProperty(name)) { - cookies.push(jar[name]); - } - } - } - return cookies; - } - - function _chooseAgent(serverURI) { - const serverHostPort = serverURI.host; - const proxy = options && options.httpProxy && options.httpProxy.uri; - if (proxy) { - let isIncluded = true; - const includes = options.httpProxy.includes; - if (includes && Array.isArray(includes)) { - isIncluded = false; - for (let i = 0; i < includes.length; ++i) { - if (new RegExp(includes[i]).test(serverHostPort)) { - isIncluded = true; - break; - } - } - } - if (isIncluded) { - const excludes = options.httpProxy.excludes; - if (excludes && Array.isArray(excludes)) { - for (let e = 0; e < excludes.length; ++e) { - if (new RegExp(excludes[e]).test(serverHostPort)) { - isIncluded = false; - break; - } - } - } - } - if (isIncluded) { - _debug('proxying', serverURI.href, 'via', proxy); - const agentOpts = Object.assign({}, _agentOptions); - return _secure(serverURI) ? new httpsProxyAgent.HttpsProxyAgent(proxy, agentOpts) : new httpcProxyAgent.HttpProxyAgent(proxy, agentOpts); - } - } - return _secure(serverURI) ? _agents : _agentc; - } - - this.status = 0; - this.statusText = ''; - this.readyState = window.XMLHttpRequest.UNSENT; - this.responseText = ''; - - this.open = (method, uri) => { - _config = new url.URL(uri); - _config.agent = _chooseAgent(_config); - _config.method = method; - _config.headers = {}; - this.readyState = window.XMLHttpRequest.OPENED; - }; - - this.setRequestHeader = (name, value) => { - if (/^cookie$/i.test(name)) { - _storeCookie(value); - } else { - _config.headers[name] = value; - } - }; - - this.send = data => { - _retrieveServerCookies(this.context, _config, (x, cookies) => { - const cookies1 = x ? '' : cookies.join('; '); - const cookies2 = _retrieveCookies().join('; '); - const delim = (cookies1 && cookies2) ? '; ' : ''; - const allCookies = cookies1 + delim + cookies2; - if (allCookies) { - _config.headers['Cookie'] = allCookies; - } - - const http = _secure(_config) ? https : httpc; - _request = http.request(_config, response => { - let success = false; - this.status = response.statusCode; - this.statusText = response.statusMessage; - this.readyState = window.XMLHttpRequest.HEADERS_RECEIVED; - const setCookies = []; - const headers = response.headers; - for (let name in headers) { - if (headers.hasOwnProperty(name)) { - if (/^set-cookie$/i.test(name)) { - const header = headers[name]; - setCookies.push.apply(setCookies, header); - } - } - } - _asyncForEach(setCookies, 0, (element, callback) => { - _storeServerCookie(_config, element, callback); - }, () => { - response.on('data', chunk => { - this.readyState = window.XMLHttpRequest.LOADING; - this.responseText += chunk; - }); - response.on('end', () => { - success = true; - this.readyState = window.XMLHttpRequest.DONE; - if (this.onload) { - this.onload(); - } - }); - response.on('close', () => { - if (!success) { - this.readyState = window.XMLHttpRequest.DONE; - if (this.onerror) { - this.onerror(); - } - } - }); - }); - }); - ['abort', 'aborted', 'error'].forEach(event => { - _request.on(event, x => { - this.readyState = window.XMLHttpRequest.DONE; - if (x) { - const error = x.message; - if (error) { - this.statusText = error; - } - } - if (this.onerror) { - this.onerror(x); - } - }); - }); - if (data) { - _request.write(data); - } - _request.end(); - }); - }; - - this.abort = () => { - if (_request) { - _request.abort(); - } - }; - - this._config = () => _config; - }; - window.XMLHttpRequest.UNSENT = 0; - window.XMLHttpRequest.OPENED = 1; - window.XMLHttpRequest.HEADERS_RECEIVED = 2; - window.XMLHttpRequest.LOADING = 3; - window.XMLHttpRequest.DONE = 4; - - window.WebSocket = ws; - } -}; + window.WebSocket = ws.WebSocket; +} diff --git a/package.json b/package.json index cb0b9b1..446cda8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cometd-nodejs-client", - "version": "1.5.0", + "version": "2.0.0", "description": "Adapter code to run the CometD JavaScript library in a NodeJS environment", "keywords": [ "node", @@ -13,27 +13,26 @@ }, "license": "Apache-2.0", "main": "cometd-nodejs-client.js", + "type": "module", "types": "cometd-nodejs-client.d.ts", "repository": { "type": "git", "url": "https://github.com/cometd/cometd-nodejs-client.git" }, "scripts": { - "test": "mocha --exit --require ts-node/register --extension ts --extension js" + "test": "mocha --exit" }, "dependencies": { - "cometd": ">=3.1.2", - "http-proxy-agent": ">=2.1.0", - "https-proxy-agent": ">=2.1.0", - "ws": ">=7.2.0" + "cometd": ">=8.0.1", + "http-proxy-agent": ">=7.0.0", + "https-proxy-agent": ">=7.0.0", + "ws": ">=8.0.0" }, "devDependencies": { "@types/mocha": ">=10.0.0", "@types/node": ">=16.0.0", - "@types/tough-cookie": "^4.0.1", - "mocha": ">=10.2.0", - "tough-cookie": "^4.0.0", - "ts-node": ">=10.9.0", - "typescript": ">=5.0.0" + "@types/tough-cookie": ">=4.0.0", + "mocha": ">=10.0.0", + "tough-cookie": ">=4.0.0" } } diff --git a/src/XMLHttpRequest.js b/src/XMLHttpRequest.js new file mode 100644 index 0000000..40cb1f2 --- /dev/null +++ b/src/XMLHttpRequest.js @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as httpc from "node:http"; +import * as https from "node:https"; +import * as httpcProxyAgent from "http-proxy-agent"; +import * as httpsProxyAgent from "https-proxy-agent"; + +// Bare minimum XMLHttpRequest implementation that works with CometD. +export class XMLHttpRequest { + static UNSENT = 0; + static OPENED = 1; + static HEADERS_RECEIVED = 2; + static LOADING = 3; + static DONE = 4; + + // Fields shared by all XMLHttpRequest instances. + static #agentOptions = { + keepAlive: true + }; + static #agentc = new httpc.Agent(XMLHttpRequest.#agentOptions); + static #agents = new https.Agent(XMLHttpRequest.#agentOptions); + + #options; + #localCookies = {}; + #config; + #request; + #readyState = XMLHttpRequest.UNSENT; + #responseText = ""; + #status = 0; + #statusText = ""; + + constructor(options) { + this.#options = options || {}; + } + + get readyState() { + return this.#readyState; + } + + get responseText() { + return this.#responseText; + } + + get status() { + return this.#status; + } + + get statusText() { + return this.#statusText; + } + + open(method, uri) { + this.#config = uri instanceof URL ? uri : new URL(uri); + this.#config.agent = this.#chooseAgent(this.#config); + this.#config.method = method; + this.#config.headers = {}; + this.#readyState = XMLHttpRequest.OPENED; + }; + + setRequestHeader(name, value) { + if (/^cookie$/i.test(name)) { + this.#storeCookie(value); + } else { + this.#config.headers[name] = value; + } + }; + + send(data) { + this.#retrieveServerCookies(this.context, this.#config, (x, cookies) => { + const cookies1 = x ? "" : cookies.join("; "); + const cookies2 = this.#retrieveCookies().join("; "); + const delim = (cookies1 && cookies2) ? "; " : ""; + const allCookies = cookies1 + delim + cookies2; + if (allCookies) { + this.#config.headers["Cookie"] = allCookies; + } + + const http = this.#secure(this.#config) ? https : httpc; + this.#request = http.request(this.#config, response => { + let success = false; + this.#status = response.statusCode; + this.#statusText = response.statusMessage; + this.#readyState = XMLHttpRequest.HEADERS_RECEIVED; + const setCookies = []; + const headers = response.headers; + for (let name in headers) { + if (headers.hasOwnProperty(name)) { + if (/^set-cookie$/i.test(name)) { + const header = headers[name]; + setCookies.push.apply(setCookies, header); + } + } + } + this.#asyncForEach(setCookies, 0, (element, callback) => { + this.#storeServerCookie(this.#config, element, callback); + }, () => { + response.on("data", chunk => { + this.#readyState = XMLHttpRequest.LOADING; + this.#responseText += chunk; + }); + response.on("end", () => { + success = true; + this.#readyState = XMLHttpRequest.DONE; + if (this.onload) { + this.onload(); + } + }); + response.on("close", () => { + if (!success) { + this.#readyState = XMLHttpRequest.DONE; + if (this.onerror) { + this.onerror(); + } + } + }); + }); + }); + ["abort", "aborted", "error"].forEach(event => { + this.#request.on(event, x => { + this.#readyState = XMLHttpRequest.DONE; + if (x) { + const error = x.message; + if (error) { + this.#statusText = error; + } + } + if (this.onerror) { + this.onerror(x); + } + }); + }); + if (data) { + this.#request.write(data); + } + this.#request.end(); + }); + }; + + abort() { + if (this.#request) { + this.#request.abort(); + } + }; + + #storeCookie(value) { + const host = this.#config.hostname; + let jar = this.#localCookies[host]; + if (jar === undefined) { + this.#localCookies[host] = jar = {}; + } + const cookies = value.split(";"); + for (let i = 0; i < cookies.length; ++i) { + const cookie = cookies[i].trim(); + const equal = cookie.indexOf("="); + if (equal > 0) { + jar[cookie.substring(0, equal)] = cookie; + } + } + } + + #retrieveCookies() { + const cookies = []; + const jar = this.#localCookies[this.#config.hostname]; + if (jar) { + for (let name in jar) { + if (jar.hasOwnProperty(name)) { + cookies.push(jar[name]); + } + } + } + return cookies; + } + + #chooseAgent(serverURI) { + const serverHostPort = serverURI.host; + const proxy = this.#options && this.#options.httpProxy && this.#options.httpProxy.uri; + if (proxy) { + let isIncluded = true; + const includes = this.#options.httpProxy.includes; + if (includes && Array.isArray(includes)) { + isIncluded = false; + for (let i = 0; i < includes.length; ++i) { + if (new RegExp(includes[i]).test(serverHostPort)) { + isIncluded = true; + break; + } + } + } + if (isIncluded) { + const excludes = this.#options.httpProxy.excludes; + if (excludes && Array.isArray(excludes)) { + for (let e = 0; e < excludes.length; ++e) { + if (new RegExp(excludes[e]).test(serverHostPort)) { + isIncluded = false; + break; + } + } + } + } + if (isIncluded) { + this.#debug("proxying", serverURI.href, "via", proxy); + const agentOpts = Object.assign({}, XMLHttpRequest.#agentOptions); + return this.#secure(serverURI) ? new httpsProxyAgent.HttpsProxyAgent(proxy, agentOpts) : new httpcProxyAgent.HttpProxyAgent(proxy, agentOpts); + } + } + return this.#secure(serverURI) ? XMLHttpRequest.#agents : XMLHttpRequest.#agentc; + } + + #storeServerCookie(uri, header, callback) { + if (this.#options && this.#options.cookies && this.#options.cookies.storeCookie) { + this.#options.cookies.storeCookie(uri, header, callback); + } else { + const host = uri.hostname; + let jar = this.#options.globalCookies[host]; + if (jar === undefined) { + this.#options.globalCookies[host] = jar = {}; + } + const parts = header.split(";"); + // Ignore domain, path, expiration, etc. + const nameValue = parts[0].trim(); + const equal = nameValue.indexOf("="); + if (equal > 0) { + const name = nameValue.substring(0, equal); + jar[name] = nameValue; + } + callback(); + } + } + + #retrieveServerCookies(context, uri, callback) { + if (this.#options && this.#options.cookies && this.#options.cookies.retrieveCookies) { + this.#options.cookies.retrieveCookies(context, uri, callback); + } else { + let globalCookies = context && context.cookieStore; + if (!globalCookies) { + globalCookies = this.#options.globalCookies; + } + let cookies = []; + const jar = globalCookies[uri.hostname]; + if (jar) { + for (let name in jar) { + if (jar.hasOwnProperty(name)) { + cookies.push(jar[name]); + } + } + } + callback(null, cookies); + } + } + + #asyncForEach(array, index, operation, callback) { + while (index < array.length) { + let complete = false; + let proceed = false; + operation(array[index], () => { + complete = true; + if (proceed) { + ++index; + this.#asyncForEach(array, index, operation, callback); + } + }); + if (complete) { + ++index; + } else { + proceed = true; + break; + } + } + if (index === array.length) { + callback(); + } + } + + #secure(uri) { + return /^https/i.test(uri.protocol); + } + + #debug() { + if (this.#options.logLevel === "debug") { + console.log.apply(this, Array.from(arguments)); + } + } +} diff --git a/test/client.js b/test/client.js index 8281a60..5d4d36e 100644 --- a/test/client.js +++ b/test/client.js @@ -13,18 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const cometd = require('..'); -const http = require('http'); +import * as nodeCometD from "../cometd-nodejs-client.js"; +import * as http from "node:http"; +import * as jsCometD from "cometd"; -describe('client', () => { - let _lib; +describe("client", () => { let _server; beforeEach(() => { - cometd.adapt(); - _lib = require('cometd'); + nodeCometD.adapt(); }); afterEach(() => { @@ -33,36 +31,38 @@ describe('client', () => { } }); - it('performs handshake', done => { + it("performs handshake", done => { _server = http.createServer((request, response) => { - let content = ''; - request.addListener('data', chunk => { + let content = ""; + request.addListener("data", chunk => { content += chunk; }); - request.addListener('end', () => { + request.addListener("end", () => { response.statusCode = 200; - response.setHeader('Content-Type', 'application/json'); - const content = '[{' + - '"id":"1",' + - '"version":"1.0",' + - '"channel":"/meta/handshake",' + - '"clientId":"0123456789abcdef",' + - '"supportedConnectionTypes":["long-polling"],' + - '"advice":{"reconnect":"none"},' + - '"successful":true' + - '}]'; - response.end(content, 'utf8'); + response.setHeader("Content-Type", "application/json"); + const content = [{ + id: "1", + version: "1.0", + channel: "/meta/handshake", + clientId: "0123456789abcdef", + supportedConnectionTypes: ["long-polling"], + successful: true, + advice: { + reconnect: "none" + } + }]; + response.end(JSON.stringify(content), "utf8"); }); }); - _server.listen(0, 'localhost', () => { + _server.listen(0, "localhost", () => { const port = _server.address().port; - console.log('listening on localhost:' + port); + console.log("listening on localhost:" + port); - const cometd = new _lib.CometD(); + const cometd = new jsCometD.CometD(); cometd.websocketEnabled = false; cometd.configure({ - url: 'http://localhost:' + port + '/cometd', - logLevel: 'info' + url: "http://localhost:" + port + "/cometd", + logLevel: "info" }); cometd.handshake(r => { if (r.successful) { diff --git a/test/cookies.ts b/test/cookies.js similarity index 57% rename from test/cookies.ts rename to test/cookies.js index 1f1d04e..3139128 100644 --- a/test/cookies.ts +++ b/test/cookies.js @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as assert from 'assert'; -import * as nodeCometD from '..'; -import * as http from 'http'; -import {AddressInfo} from 'net'; -import * as tough from 'tough-cookie'; -describe('cookies', () => { - let _server: http.Server; +import * as assert from "node:assert"; +import * as nodeCometD from "../cometd-nodejs-client.js"; +import * as http from "node:http"; +import * as tough from "tough-cookie"; + +describe("cookies", () => { + let _server; afterEach(() => { if (_server) { @@ -28,30 +28,30 @@ describe('cookies', () => { } }); - it('receives, stores and sends cookie', done => { + it("receives, stores and sends cookie", done => { nodeCometD.adapt(); - const cookie = 'a=b'; + const cookie = "a=b"; _server = http.createServer((request, response) => { - const uri: string = request.url || '/'; + const uri = request.url || "/"; if (/\/1$/.test(uri)) { - response.setHeader('Set-Cookie', cookie); + response.setHeader("Set-Cookie", cookie); response.end(); } else if (/\/2$/.test(uri)) { - assert.strictEqual(request.headers['cookie'], cookie); + assert.strictEqual(request.headers["cookie"], cookie); response.end(); } }); - _server.listen(0, 'localhost', () => { - const port = (_server.address() as AddressInfo).port - console.log('listening on localhost:' + port); - const uri = 'http://localhost:' + port; + _server.listen(0, "localhost", () => { + const port = _server.address().port + console.log("listening on localhost:" + port); + const uri = "http://localhost:" + port; const xhr1 = new window.XMLHttpRequest(); - xhr1.open('GET', uri + '/1'); + xhr1.open("GET", uri + "/1"); xhr1.onload = () => { assert.strictEqual(xhr1.status, 200); const xhr2 = new window.XMLHttpRequest(); - xhr2.open('GET', uri + '/2'); + xhr2.open("GET", uri + "/2"); xhr2.onload = () => { assert.strictEqual(xhr2.status, 200); done(); @@ -62,39 +62,39 @@ describe('cookies', () => { }); }); - it('sends multiple cookies', done => { + it("sends multiple cookies", done => { nodeCometD.adapt(); - const cookie1 = 'a=b'; - const cookie2 = 'c=d'; - const cookies = cookie1 + '; ' + cookie2; + const cookie1 = "a=b"; + const cookie2 = "c=d"; + const cookies = cookie1 + "; " + cookie2; _server = http.createServer((request, response) => { - const uri: string = request.url || '/'; + const uri = request.url || "/"; if (/\/1$/.test(uri)) { - response.setHeader('Set-Cookie', cookie1); + response.setHeader("Set-Cookie", cookie1); response.end(); } else if (/\/2$/.test(uri)) { - response.setHeader('Set-Cookie', cookie2); + response.setHeader("Set-Cookie", cookie2); response.end(); } else if (/\/3$/.test(uri)) { - assert.strictEqual(request.headers['cookie'], cookies); + assert.strictEqual(request.headers["cookie"], cookies); response.end(); } }); - _server.listen(0, 'localhost', () => { - const port = (_server.address() as AddressInfo).port - console.log('listening on localhost:' + port); - const uri = 'http://localhost:' + port; + _server.listen(0, "localhost", () => { + const port = _server.address().port + console.log("listening on localhost:" + port); + const uri = "http://localhost:" + port; const xhr1 = new window.XMLHttpRequest(); - xhr1.open('GET', uri + '/1'); + xhr1.open("GET", uri + "/1"); xhr1.onload = () => { assert.strictEqual(xhr1.status, 200); const xhr2 = new window.XMLHttpRequest(); - xhr2.open('GET', uri + '/2'); + xhr2.open("GET", uri + "/2"); xhr2.onload = () => { assert.strictEqual(xhr2.status, 200); const xhr3 = new window.XMLHttpRequest(); - xhr3.open('GET', uri + '/3'); + xhr3.open("GET", uri + "/3"); xhr3.onload = () => { assert.strictEqual(xhr3.status, 200); done(); @@ -107,49 +107,49 @@ describe('cookies', () => { }); }); - it('handles cookies from different hosts', done => { + it("handles cookies from different hosts", done => { nodeCometD.adapt(); - const cookieA = 'a=b'; - const cookieB = 'b=c'; + const cookieA = "a=b"; + const cookieB = "b=c"; _server = http.createServer((request, response) => { - const uri: string = request.url || '/'; + const uri = request.url || "/"; if (/\/hostA\//.test(uri)) { if (/\/1$/.test(uri)) { - response.setHeader('Set-Cookie', cookieA); + response.setHeader("Set-Cookie", cookieA); response.end(); } else if (/\/2$/.test(uri)) { - assert.strictEqual(request.headers['cookie'], cookieA); + assert.strictEqual(request.headers["cookie"], cookieA); response.end(); } } else if (/\/hostB\//.test(uri)) { if (/\/1$/.test(uri)) { - response.setHeader('Set-Cookie', cookieB); + response.setHeader("Set-Cookie", cookieB); response.end(); } else if (/\/2$/.test(uri)) { - assert.strictEqual(request.headers['cookie'], cookieB); + assert.strictEqual(request.headers["cookie"], cookieB); response.end(); } } }); - _server.listen(0, 'localhost', () => { - const port = (_server.address() as AddressInfo).port - console.log('listening on localhost:' + port); + _server.listen(0, "localhost", () => { + const port = _server.address().port + console.log("listening on localhost:" + port); const xhrA1 = new window.XMLHttpRequest(); - xhrA1.open('GET', 'http://localhost:' + port + '/hostA/1'); + xhrA1.open("GET", "http://localhost:" + port + "/hostA/1"); xhrA1.onload = () => { assert.strictEqual(xhrA1.status, 200); const xhrA2 = new window.XMLHttpRequest(); - xhrA2.open('GET', 'http://localhost:' + port + '/hostA/2'); + xhrA2.open("GET", "http://localhost:" + port + "/hostA/2"); xhrA2.onload = () => { assert.strictEqual(xhrA2.status, 200); const xhrB1 = new window.XMLHttpRequest(); - xhrB1.open('GET', 'http://127.0.0.1:' + port + '/hostB/1'); + xhrB1.open("GET", "http://127.0.0.1:" + port + "/hostB/1"); xhrB1.onload = () => { assert.strictEqual(xhrB1.status, 200); const xhrB2 = new window.XMLHttpRequest(); - xhrB2.open('GET', 'http://127.0.0.1:' + port + '/hostB/2'); + xhrB2.open("GET", "http://127.0.0.1:" + port + "/hostB/2"); xhrB2.onload = () => { assert.strictEqual(xhrB2.status, 200); done(); @@ -164,35 +164,35 @@ describe('cookies', () => { }); }); - it('handles cookie sent multiple times', done => { + it("handles cookie sent multiple times", done => { nodeCometD.adapt(); - const cookieName = 'a'; - const cookieValue = 'b'; - const cookie = cookieName + '=' + cookieValue; + const cookieName = "a"; + const cookieValue = "b"; + const cookie = cookieName + "=" + cookieValue; _server = http.createServer((request, response) => { - const uri: string = request.url || '/'; + const uri = request.url || "/"; if (/\/verify$/.test(uri)) { - assert.strictEqual(request.headers['cookie'], cookie); + assert.strictEqual(request.headers["cookie"], cookie); response.end(); } else { - response.setHeader('Set-Cookie', cookie); + response.setHeader("Set-Cookie", cookie); response.end(); } }); - _server.listen(0, 'localhost', () => { - const port = (_server.address() as AddressInfo).port - console.log('listening on localhost:' + port); + _server.listen(0, "localhost", () => { + const port = _server.address().port + console.log("listening on localhost:" + port); const xhr1 = new window.XMLHttpRequest(); - xhr1.open('GET', 'http://localhost:' + port + '/1'); + xhr1.open("GET", "http://localhost:" + port + "/1"); xhr1.onload = () => { assert.strictEqual(xhr1.status, 200); const xhr2 = new window.XMLHttpRequest(); - xhr2.open('GET', 'http://localhost:' + port + '/2'); + xhr2.open("GET", "http://localhost:" + port + "/2"); xhr2.onload = () => { assert.strictEqual(xhr2.status, 200); const xhr3 = new window.XMLHttpRequest(); - xhr3.open('GET', 'http://localhost:' + port + '/verify'); + xhr3.open("GET", "http://localhost:" + port + "/verify"); xhr3.onload = () => { assert.strictEqual(xhr1.status, 200); done(); @@ -205,41 +205,41 @@ describe('cookies', () => { }); }); - it('handles cookies as request headers', done => { + it("handles cookies as request headers", done => { nodeCometD.adapt(); _server = http.createServer((request, response) => { - const cookies = request.headers['cookie'] || ''; - const uri: string = request.url || '/'; + const cookies = request.headers["cookie"] || ""; + const uri = request.url || "/"; if (/\/1$/.test(uri)) { - response.setHeader('Set-Cookie', 'a=b'); + response.setHeader("Set-Cookie", "a=b"); response.end(); } else if (/\/2$/.test(uri)) { - assert.ok(cookies.indexOf('a=b') >= 0); - assert.ok(cookies.indexOf('c=d') >= 0); - assert.ok(cookies.indexOf('e=f') >= 0); + assert.ok(cookies.indexOf("a=b") >= 0); + assert.ok(cookies.indexOf("c=d") >= 0); + assert.ok(cookies.indexOf("e=f") >= 0); response.end(); } else if (/\/3$/.test(uri)) { - assert.ok(cookies.indexOf('a=b') >= 0); - assert.ok(cookies.indexOf('c=d') < 0); - assert.ok(cookies.indexOf('e=f') < 0); + assert.ok(cookies.indexOf("a=b") >= 0); + assert.ok(cookies.indexOf("c=d") < 0); + assert.ok(cookies.indexOf("e=f") < 0); response.end(); } }); - _server.listen(0, 'localhost', () => { - const port = (_server.address() as AddressInfo).port - console.log('listening on localhost:' + port); + _server.listen(0, "localhost", () => { + const port = _server.address().port + console.log("listening on localhost:" + port); const xhr1 = new window.XMLHttpRequest(); - xhr1.open('GET', 'http://localhost:' + port + '/1'); + xhr1.open("GET", "http://localhost:" + port + "/1"); xhr1.onload = () => { assert.strictEqual(xhr1.status, 200); const xhr2 = new window.XMLHttpRequest(); - xhr2.open('GET', 'http://localhost:' + port + '/2'); - xhr2.setRequestHeader('cookie', 'c=d; e=f'); + xhr2.open("GET", "http://localhost:" + port + "/2"); + xhr2.setRequestHeader("cookie", "c=d; e=f"); xhr2.onload = () => { assert.strictEqual(xhr2.status, 200); const xhr3 = new window.XMLHttpRequest(); - xhr3.open('GET', 'http://localhost:' + port + '/3'); + xhr3.open("GET", "http://localhost:" + port + "/3"); xhr3.onload = () => { assert.strictEqual(xhr3.status, 200); done(); @@ -252,23 +252,23 @@ describe('cookies', () => { }); }); - it('allows custom cookie handling', done => { + it("allows custom cookie handling", done => { const cookieJar = new tough.CookieJar(); nodeCometD.adapt({ cookies: { - storeCookie(uri: any, header: string, callback: (failure: Error | null, cookie: any) => void) { + storeCookie(uri, header, callback) { const cookie = tough.Cookie.parse(header); if (cookie) { cookieJar.setCookie(cookie, uri.toString(), // Test both sync and async callbacks. - header.startsWith('a=1') ? callback : () => setTimeout(callback, 0)); + header.startsWith("a=1") ? callback : () => setTimeout(callback, 0)); } else { callback(null, cookie); } }, - retrieveCookies(context: any, uri: any, callback: (failure: Error | null, cookies: string[]) => void) { - cookieJar.getCookies(uri.toString(), (x: any, r: tough.Cookie[]) => { - const result: string[] = x ? [] : r.map(c => c.cookieString()); + retrieveCookies(context, uri, callback) { + cookieJar.getCookies(uri.toString(), (x, r) => { + const result = x ? [] : r.map(c => c.cookieString()); callback(x, result); }); } @@ -276,32 +276,32 @@ describe('cookies', () => { }); _server = http.createServer((request, response) => { - const cookies = request.headers['cookie'] || ''; - const uri: string = request.url || '/'; + const cookies = request.headers["cookie"] || ""; + const uri = request.url || "/"; if (/\/set$/.test(uri)) { - response.setHeader('Set-Cookie', ['a=1; Path=/', 'b=2; Path=/b']); + response.setHeader("Set-Cookie", ["a=1; Path=/", "b=2; Path=/b"]); } else if (/\/b$/.test(uri)) { - assert.ok(cookies.indexOf('a=1') >= 0); - assert.ok(cookies.indexOf('b=2') >= 0); + assert.ok(cookies.indexOf("a=1") >= 0); + assert.ok(cookies.indexOf("b=2") >= 0); } else { - assert.ok(cookies.indexOf('a=1') >= 0); + assert.ok(cookies.indexOf("a=1") >= 0); } response.end(); }); - _server.listen(0, 'localhost', () => { - const port = (_server.address() as AddressInfo).port - console.log('listening on localhost:' + port); + _server.listen(0, "localhost", () => { + const port = _server.address().port + console.log("listening on localhost:" + port); const xhr1 = new window.XMLHttpRequest(); - xhr1.open('GET', 'http://localhost:' + port + '/set'); + xhr1.open("GET", "http://localhost:" + port + "/set"); xhr1.onload = () => { assert.strictEqual(xhr1.status, 200); const xhr2 = new window.XMLHttpRequest(); - xhr2.open('GET', 'http://localhost:' + port + '/a'); + xhr2.open("GET", "http://localhost:" + port + "/a"); xhr2.onload = () => { assert.strictEqual(xhr2.status, 200); const xhr3 = new window.XMLHttpRequest(); - xhr3.open('GET', 'http://localhost:' + port + '/b'); + xhr3.open("GET", "http://localhost:" + port + "/b"); xhr3.onload = () => { assert.strictEqual(xhr3.status, 200); done(); diff --git a/test/https.js b/test/https.js index dc50fe5..d06c1a3 100644 --- a/test/https.js +++ b/test/https.js @@ -13,19 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const assert = require('assert'); -const cometd = require('..'); -const https = require('https'); -const fs = require('fs'); +import * as assert from "node:assert"; +import * as nodeCometD from "../cometd-nodejs-client.js"; +import * as https from "node:https"; +import * as fs from "node:fs"; -describe('https', () => { +describe("https", () => { let _runtime; let _server; beforeEach(() => { - cometd.adapt(); + nodeCometD.adapt(); _runtime = global.window; }); @@ -35,22 +34,23 @@ describe('https', () => { } }); - it('supports https', done => { + it("supports https", done => { const options = { - key: fs.readFileSync('test/tls/private.pem'), - cert: fs.readFileSync('test/tls/public.pem') + key: fs.readFileSync("test/tls/private.pem"), + cert: fs.readFileSync("test/tls/public.pem") }; _server = https.createServer(options, (request, response) => { response.end(); }); - _server.listen(0, 'localhost', () => { + _server.listen(0, "localhost", () => { const port = _server.address().port; - console.log('listening on localhost:' + port); - const uri = 'https://localhost:' + port; + console.log("listening on localhost:" + port); + const uri = "https://localhost:" + port; const xhr = new _runtime.XMLHttpRequest(); - xhr.open('GET', uri + '/'); + const url = new URL(uri + "/"); // Allow self-signed certificates. - xhr._config().rejectUnauthorized = false; + url.rejectUnauthorized = false; + xhr.open("GET", url); xhr.onload = () => { assert.strictEqual(xhr.status, 200); done(); diff --git a/test/library.js b/test/library.js index 9f3dd84..d3125b0 100644 --- a/test/library.js +++ b/test/library.js @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const assert = require('assert'); -const cometd = require('..'); +import * as assert from "node:assert"; +import * as nodeCometD from "../cometd-nodejs-client.js"; -describe('library', () => { - it('adapter method exported', () => { - assert.ok(cometd.adapt); +describe("library", () => { + it("adapter method exported", () => { + assert.ok(nodeCometD.adapt); }); }); diff --git a/test/proxy.js b/test/proxy.js index f6e37a9..9ed75b0 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -13,15 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const assert = require('assert'); -const nodeCometD = require('..'); -const http = require('http'); -const url = require('url'); +import * as assert from "node:assert"; +import * as nodeCometD from "../cometd-nodejs-client.js"; +import * as http from "node:http"; +import * as jsCometD from "cometd"; -describe('proxy', () => { - const _lib = require('cometd'); +describe("proxy", () => { let _proxy; afterEach(() => { @@ -30,49 +28,51 @@ describe('proxy', () => { } }); - it('proxies cometd calls', done => { + it("proxies cometd calls", done => { _proxy = http.createServer((request, response) => { - const serverPort = parseInt(url.parse(request.url).port); + const serverPort = parseInt(new URL(request.url).port); assert.ok(Number.isInteger(serverPort)); assert.notStrictEqual(serverPort, _proxy.address().port); - let content = ''; - request.addListener('data', chunk => { + let content = ""; + request.addListener("data", chunk => { content += chunk; }); - request.addListener('end', () => { + request.addListener("end", () => { response.statusCode = 200; - response.setHeader('Content-Type', 'application/json'); - const content = '[{' + - '"id":"1",' + - '"version":"1.0",' + - '"channel":"/meta/handshake",' + - '"clientId":"0123456789abcdef",' + - '"supportedConnectionTypes":["long-polling"],' + - '"advice":{"reconnect":"none"},' + - '"successful":true' + - '}]'; - response.end(content, 'utf8'); + response.setHeader("Content-Type", "application/json"); + const content = [{ + id: "1", + version: "1.0", + channel: "/meta/handshake", + clientId: "0123456789abcdef", + supportedConnectionTypes: ["long-polling"], + successful: true, + advice: { + reconnect: "none" + } + }]; + response.end(JSON.stringify(content), "utf8"); }); }); - _proxy.listen(0, 'localhost', () => { + _proxy.listen(0, "localhost", () => { const proxyPort = _proxy.address().port; - console.log('proxy listening on localhost:' + proxyPort); + console.log("proxy listening on localhost:" + proxyPort); nodeCometD.adapt({ - logLevel: 'debug', + logLevel: "debug", httpProxy: { - uri: 'http://localhost:' + proxyPort + uri: "http://localhost:" + proxyPort } }); // Any port will do for the server. const serverPort = proxyPort + 1; - const cometd = new _lib.CometD(); + const cometd = new jsCometD.CometD(); cometd.websocketEnabled = false; cometd.configure({ - url: 'http://localhost:' + serverPort + '/cometd', - logLevel: 'info' + url: "http://localhost:" + serverPort + "/cometd", + logLevel: "info" }); cometd.handshake(r => { if (r.successful) { @@ -80,68 +80,70 @@ describe('proxy', () => { } else { // Stop /meta/handshake retries. cometd.disconnect(); - done(new Error('could not handshake')); + done(new Error("could not handshake")); } }); }); }); - it('proxies with includes list', done => { + it("proxies with includes list", done => { _proxy = http.createServer((request, response) => { - const serverPort = parseInt(url.parse(request.url).port); + const serverPort = parseInt(new URL(request.url).port); assert.ok(Number.isInteger(serverPort)); assert.notStrictEqual(serverPort, _proxy.address().port); - let content = ''; - request.addListener('data', chunk => { + let content = ""; + request.addListener("data", chunk => { content += chunk; }); - request.addListener('end', () => { + request.addListener("end", () => { response.statusCode = 200; - response.setHeader('Content-Type', 'application/json'); - const content = '[{' + - '"id":"1",' + - '"version":"1.0",' + - '"channel":"/meta/handshake",' + - '"clientId":"0123456789abcdef",' + - '"supportedConnectionTypes":["long-polling"],' + - '"advice":{"reconnect":"none"},' + - '"successful":true' + - '}]'; - response.end(content, 'utf8'); + response.setHeader("Content-Type", "application/json"); + const content = [{ + id: "1", + version: "1.0", + channel: "/meta/handshake", + clientId: "0123456789abcdef", + supportedConnectionTypes: ["long-polling"], + successful: true, + advice: { + reconnect: "none" + } + }]; + response.end(JSON.stringify(content), "utf8"); }); }); - _proxy.listen(0, 'localhost', () => { + _proxy.listen(0, "localhost", () => { const proxyPort = _proxy.address().port; - console.log('proxy listening on localhost:' + proxyPort); + console.log("proxy listening on localhost:" + proxyPort); // Any port will do for the server. const serverPort1 = proxyPort + 1; const serverPort2 = proxyPort + 2; nodeCometD.adapt({ httpProxy: { - uri: 'http://localhost:' + proxyPort, - includes: ['localhost:' + serverPort1] + uri: "http://localhost:" + proxyPort, + includes: ["localhost:" + serverPort1] } }); - const cometd1 = new _lib.CometD(); + const cometd1 = new jsCometD.CometD(); cometd1.websocketEnabled = false; cometd1.configure({ - url: 'http://localhost:' + serverPort1 + '/cometd', - logLevel: 'info' + url: "http://localhost:" + serverPort1 + "/cometd", + logLevel: "info" }); cometd1.handshake(r => { if (r.successful) { - const cometd2 = new _lib.CometD(); + const cometd2 = new jsCometD.CometD(); cometd2.websocketEnabled = false; cometd2.configure({ - url: 'http://localhost:' + serverPort2 + '/cometd', - logLevel: 'info' + url: "http://localhost:" + serverPort2 + "/cometd", + logLevel: "info" }); cometd2.handshake(r => { if (r.successful) { - done(new Error('must not handshake')); + done(new Error("must not handshake")); } else { // Stop /meta/handshake retries. cometd2.disconnect(); @@ -150,68 +152,70 @@ describe('proxy', () => { }); } else { cometd1.disconnect(); - done(new Error('could not handshake')); + done(new Error("could not handshake")); } }); }); }); - it('proxies with excludes list', done => { + it("proxies with excludes list", done => { _proxy = http.createServer((request, response) => { - const serverPort = parseInt(url.parse(request.url).port); + const serverPort = parseInt(new URL(request.url).port); assert.ok(Number.isInteger(serverPort)); assert.notStrictEqual(serverPort, _proxy.address().port); - let content = ''; - request.addListener('data', chunk => { + let content = ""; + request.addListener("data", chunk => { content += chunk; }); - request.addListener('end', () => { + request.addListener("end", () => { response.statusCode = 200; - response.setHeader('Content-Type', 'application/json'); - const content = '[{' + - '"id":"1",' + - '"version":"1.0",' + - '"channel":"/meta/handshake",' + - '"clientId":"0123456789abcdef",' + - '"supportedConnectionTypes":["long-polling"],' + - '"advice":{"reconnect":"none"},' + - '"successful":true' + - '}]'; - response.end(content, 'utf8'); + response.setHeader("Content-Type", "application/json"); + const content = [{ + id: "1", + version: "1.0", + channel: "/meta/handshake", + clientId: "0123456789abcdef", + supportedConnectionTypes: ["long-polling"], + successful: true, + advice: { + reconnect: "none" + } + }]; + response.end(JSON.stringify(content), "utf8"); }); }); - _proxy.listen(0, 'localhost', () => { + _proxy.listen(0, "localhost", () => { const proxyPort = _proxy.address().port; - console.log('proxy listening on localhost:' + proxyPort); + console.log("proxy listening on localhost:" + proxyPort); // Any port will do for the server. const serverPort1 = proxyPort + 1; const serverPort2 = proxyPort + 2; nodeCometD.adapt({ httpProxy: { - uri: 'http://localhost:' + proxyPort, - excludes: ['local.*:' + serverPort1] + uri: "http://localhost:" + proxyPort, + excludes: ["local.*:" + serverPort1] } }); - const cometd1 = new _lib.CometD(); + const cometd1 = new jsCometD.CometD(); cometd1.websocketEnabled = false; cometd1.configure({ - url: 'http://localhost:' + serverPort1 + '/cometd', - logLevel: 'info' + url: "http://localhost:" + serverPort1 + "/cometd", + logLevel: "info" }); cometd1.handshake(r => { if (r.successful) { - done(new Error('could not handshake')); + done(new Error("could not handshake")); } else { // Stop /meta/handshake retries. cometd1.disconnect(); - const cometd2 = new _lib.CometD(); + const cometd2 = new jsCometD.CometD(); cometd2.websocketEnabled = false; cometd2.configure({ - url: 'http://localhost:' + serverPort2 + '/cometd', - logLevel: 'info' + url: "http://localhost:" + serverPort2 + "/cometd", + logLevel: "info" }); cometd2.handshake(r => { if (r.successful) { @@ -219,7 +223,7 @@ describe('proxy', () => { } else { // Stop /meta/handshake retries. cometd2.disconnect(); - done(new Error('must not handshake')); + done(new Error("must not handshake")); } }); } @@ -227,63 +231,65 @@ describe('proxy', () => { }); }); - it('proxies with includes and excludes list', done => { + it("proxies with includes and excludes list", done => { _proxy = http.createServer((request, response) => { - const serverPort = parseInt(url.parse(request.url).port); + const serverPort = parseInt(new URL(request.url).port); assert.ok(Number.isInteger(serverPort)); assert.notStrictEqual(serverPort, _proxy.address().port); - let content = ''; - request.addListener('data', chunk => { + let content = ""; + request.addListener("data", chunk => { content += chunk; }); - request.addListener('end', () => { + request.addListener("end", () => { response.statusCode = 200; - response.setHeader('Content-Type', 'application/json'); - const content = '[{' + - '"id":"1",' + - '"version":"1.0",' + - '"channel":"/meta/handshake",' + - '"clientId":"0123456789abcdef",' + - '"supportedConnectionTypes":["long-polling"],' + - '"advice":{"reconnect":"none"},' + - '"successful":true' + - '}]'; - response.end(content, 'utf8'); + response.setHeader("Content-Type", "application/json"); + const content = [{ + id: "1", + version: "1.0", + channel: "/meta/handshake", + clientId: "0123456789abcdef", + supportedConnectionTypes: ["long-polling"], + successful: true, + advice: { + reconnect: "none" + } + }]; + response.end(JSON.stringify(content), "utf8"); }); }); - _proxy.listen(0, 'localhost', () => { + _proxy.listen(0, "localhost", () => { const proxyPort = _proxy.address().port; - console.log('proxy listening on localhost:' + proxyPort); + console.log("proxy listening on localhost:" + proxyPort); // Any port will do for the server. const serverPort1 = proxyPort + 1; const serverPort2 = proxyPort + 2; nodeCometD.adapt({ httpProxy: { - uri: 'http://localhost:' + proxyPort, - includes: ['.*:' + serverPort1, '.*host:' + serverPort2], - excludes: ['local.*:' + serverPort1] + uri: "http://localhost:" + proxyPort, + includes: [".*:" + serverPort1, ".*host:" + serverPort2], + excludes: ["local.*:" + serverPort1] } }); - const cometd1 = new _lib.CometD(); + const cometd1 = new jsCometD.CometD(); cometd1.websocketEnabled = false; cometd1.configure({ - url: 'http://localhost:' + serverPort1 + '/cometd', - logLevel: 'info' + url: "http://localhost:" + serverPort1 + "/cometd", + logLevel: "info" }); cometd1.handshake(r => { if (r.successful) { - done(new Error('could not handshake')); + done(new Error("could not handshake")); } else { // Stop /meta/handshake retries. cometd1.disconnect(); - const cometd2 = new _lib.CometD(); + const cometd2 = new jsCometD.CometD(); cometd2.websocketEnabled = false; cometd2.configure({ - url: 'http://localhost:' + serverPort2 + '/cometd', - logLevel: 'info' + url: "http://localhost:" + serverPort2 + "/cometd", + logLevel: "info" }); cometd2.handshake(r => { if (r.successful) { @@ -291,7 +297,7 @@ describe('proxy', () => { } else { // Stop /meta/handshake retries. cometd2.disconnect(); - done(new Error('must not handshake')); + done(new Error("must not handshake")); } }); } @@ -299,48 +305,50 @@ describe('proxy', () => { }); }); - it('proxies with authentication', done => { + it("proxies with authentication", done => { _proxy = http.createServer((request, response) => { - const proxyAuth = request.headers['proxy-authorization']; + const proxyAuth = request.headers["proxy-authorization"]; assert.ok(proxyAuth); - assert.ok(proxyAuth.startsWith('Basic ')); + assert.ok(proxyAuth.startsWith("Basic ")); - let content = ''; - request.addListener('data', chunk => { + let content = ""; + request.addListener("data", chunk => { content += chunk; }); - request.addListener('end', () => { + request.addListener("end", () => { response.statusCode = 200; - response.setHeader('Content-Type', 'application/json'); - const content = '[{' + - '"id":"1",' + - '"version":"1.0",' + - '"channel":"/meta/handshake",' + - '"clientId":"0123456789abcdef",' + - '"supportedConnectionTypes":["long-polling"],' + - '"advice":{"reconnect":"none"},' + - '"successful":true' + - '}]'; - response.end(content, 'utf8'); + response.setHeader("Content-Type", "application/json"); + const content = [{ + id: "1", + version: "1.0", + channel: "/meta/handshake", + clientId: "0123456789abcdef", + supportedConnectionTypes: ["long-polling"], + successful: true, + advice: { + reconnect: "none" + } + }]; + response.end(JSON.stringify(content), "utf8"); }); }); - _proxy.listen(0, 'localhost', () => { + _proxy.listen(0, "localhost", () => { const proxyPort = _proxy.address().port; - console.log('proxy listening on localhost:' + proxyPort); + console.log("proxy listening on localhost:" + proxyPort); nodeCometD.adapt({ httpProxy: { - uri: 'http://user:password@localhost:' + proxyPort + uri: "http://user:password@localhost:" + proxyPort } }); // Any port will do for the server. const serverPort = proxyPort + 1; - const cometd = new _lib.CometD(); + const cometd = new jsCometD.CometD(); cometd.websocketEnabled = false; cometd.configure({ - url: 'http://localhost:' + serverPort + '/cometd', - logLevel: 'info' + url: "http://localhost:" + serverPort + "/cometd", + logLevel: "info" }); cometd.handshake(r => { if (r.successful) { @@ -348,7 +356,7 @@ describe('proxy', () => { } else { // Stop /meta/handshake retries. cometd.disconnect(); - done(new Error('could not handshake')); + done(new Error("could not handshake")); } }); }); diff --git a/test/ts_client.ts b/test/ts_client.ts deleted file mode 100644 index 8321bce..0000000 --- a/test/ts_client.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import * as nodeCometD from '..'; -import * as jsCometD from 'cometd'; -import * as http from 'http'; -import {AddressInfo} from 'net'; - -describe('typescript client', () => { - let _server: http.Server; - - beforeEach(() => { - nodeCometD.adapt(); - }); - - afterEach(() => { - if (_server) { - _server.close(); - } - }); - - it('performs handshake', done => { - _server = http.createServer((request, response) => { - let content = ''; - request.addListener('data', chunk => { - content += chunk; - }); - request.addListener('end', () => { - response.statusCode = 200; - response.setHeader('Content-Type', 'application/json'); - const content = '[{' + - '"id":"1",' + - '"version":"1.0",' + - '"channel":"/meta/handshake",' + - '"clientId":"0123456789abcdef",' + - '"supportedConnectionTypes":["long-polling"],' + - '"advice":{"reconnect":"none"},' + - '"successful":true' + - '}]'; - response.end(content, 'utf8'); - }); - }); - _server.listen(0, 'localhost', () => { - const port = (_server.address() as AddressInfo).port - console.log('listening on localhost:' + port); - - const cometd: jsCometD.CometD = new jsCometD.CometD(); - cometd.websocketEnabled = false; - cometd.configure({ - url: 'http://localhost:' + port + '/cometd', - logLevel: 'info' - }); - cometd.handshake((r: jsCometD.Message) => { - if (r.successful) { - done(); - } - }); - }); - }); -}); diff --git a/test/websocket.js b/test/websocket.js index de459a2..ab61a71 100644 --- a/test/websocket.js +++ b/test/websocket.js @@ -13,14 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const assert = require('assert'); -const nodeCometD = require('..'); -const ws = require("ws"); +import * as assert from "node:assert"; +import * as nodeCometD from "../cometd-nodejs-client.js"; +import * as ws from "ws"; +import * as jsCometD from "cometd"; -describe('websocket', () => { - const _lib = require('cometd'); +describe("websocket", () => { let _server; afterEach(() => { @@ -29,22 +28,22 @@ describe('websocket', () => { } }); - it('handshakes with websocket', done => { - _server = new ws.Server({port: 0}, () => { - _server.on('connection', s => { - s.on('message', m => { + it("handshakes with websocket", done => { + _server = new ws.WebSocketServer({ port: 0 }, () => { + _server.on("connection", s => { + s.on("message", m => { const handshake = JSON.parse(m)[0]; - assert.strictEqual('/meta/handshake', handshake.channel); - assert.ok(handshake.supportedConnectionTypes.indexOf('websocket') >= 0); + assert.strictEqual("/meta/handshake", handshake.channel); + assert.ok(handshake.supportedConnectionTypes.indexOf("websocket") >= 0); const reply = [{ id: handshake.id, channel: handshake.channel, successful: true, version: "1.0", - supportedConnectionTypes: ['websocket'], - clientId: '0123456789abcdef', + supportedConnectionTypes: ["websocket"], + clientId: "0123456789abcdef", advice: { - reconnect: 'none' + reconnect: "none" } }]; s.send(JSON.stringify(reply)); @@ -52,17 +51,17 @@ describe('websocket', () => { }); nodeCometD.adapt(); - const cometd = new _lib.CometD(); + const cometd = new jsCometD.CometD(); cometd.configure({ - url: 'http://localhost:' + _server.address().port, - logLevel: 'info' + url: "http://localhost:" + _server.address().port, + logLevel: "info" }); cometd.handshake(r => { if (r.successful) { done(); } else { cometd.disconnect(); - done(new Error('could not handshake')); + done(new Error("could not handshake")); } }); }); diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 0fe86e7..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "target": "ES6", - "module": "CommonJS", - "outDir": "test", - "strict": true, - "noImplicitAny": true - }, - "include": ["test/*.ts"], - "exclude": [] -}