From eb5f404cfa7c4a5a9f29fee65cf1313602299926 Mon Sep 17 00:00:00 2001 From: DavideViolante Date: Fri, 4 Jul 2025 13:04:19 +0200 Subject: [PATCH 1/8] feat: add github action to test a ts project and build it --- .github/workflows/typescript-build-test.yml | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/typescript-build-test.yml diff --git a/.github/workflows/typescript-build-test.yml b/.github/workflows/typescript-build-test.yml new file mode 100644 index 000000000..15259589a --- /dev/null +++ b/.github/workflows/typescript-build-test.yml @@ -0,0 +1,35 @@ +name: TypeScript Compatibility Test + +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + +jobs: + typescript-compat: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Build MQTT.js + run: | + npm ci + npm run build + + - name: Create test TypeScript project + run: | + mkdir ts-test + cd ts-test + npm init -y + npm install typescript@5.x + npm install ../ + echo "import * as mqtt from 'mqtt'; const client = mqtt.connect('ws://localhost');" > index.ts + echo '{ "compilerOptions": { "esModuleInterop": true, "strict": true } }' > tsconfig.json + npx tsc -p . From ff11431512d382f43919166d510c1484aafa2870 Mon Sep 17 00:00:00 2001 From: DavideViolante Date: Tue, 8 Jul 2025 13:52:20 +0200 Subject: [PATCH 2/8] chore: restore no unused vars rule, except for fn params --- .eslintrc.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 49b0d7c20..a56ce1dba 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -22,11 +22,10 @@ module.exports = { rules: { 'global-require': 'off', 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', - 'no-unused-vars': 'off', + 'no-unused-vars': ['error', { args: 'none' }], 'no-underscore-dangle': 'off', 'no-param-reassign': 'off', 'no-restricted-syntax': 'off', - camelcase: 'off', 'default-case': 'off', 'consistent-return': 'off', 'import/order': 'off', @@ -43,7 +42,10 @@ module.exports = { '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { args: 'none' } + ], '@typescript-eslint/naming-convention': 'off', '@typescript-eslint/dot-notation': 'off', '@typescript-eslint/no-use-before-define': 'off', From e72502ef549b2991e4d444eac6c89e54f41986de Mon Sep 17 00:00:00 2001 From: DavideViolante Date: Tue, 8 Jul 2025 13:53:55 +0200 Subject: [PATCH 3/8] chore: restore import order and run lint-fix --- .eslintrc.js | 1 - src/bin/pub.ts | 2 +- src/bin/sub.ts | 2 +- src/lib/client.ts | 14 +++++++------- src/lib/connect/socks.ts | 2 +- src/lib/connect/tcp.ts | 3 +-- src/lib/connect/ws.ts | 2 +- src/lib/connect/wx.ts | 3 +-- src/lib/get-timer.ts | 2 +- src/lib/handlers/connack.ts | 2 +- test/node/abstract_client.ts | 18 +++++++++--------- test/node/abstract_store.ts | 4 ++-- test/node/client.ts | 8 ++++---- test/node/client_mqtt5.ts | 2 +- test/node/keepaliveManager.ts | 2 +- test/node/message-id-provider.ts | 2 +- test/node/mqtt.ts | 2 +- test/node/mqtt_store.ts | 2 +- test/node/secure_client.ts | 4 ++-- test/node/server_helpers_for_client_tests.ts | 2 +- test/node/store.ts | 2 +- test/node/unique_message_id_provider_client.ts | 2 +- test/node/websocket_client.ts | 2 +- 23 files changed, 41 insertions(+), 44 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index a56ce1dba..be8a30890 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -28,7 +28,6 @@ module.exports = { 'no-restricted-syntax': 'off', 'default-case': 'off', 'consistent-return': 'off', - 'import/order': 'off', 'max-classes-per-file': 'off', 'no-plusplus': 'off', 'guard-for-in': 'off', diff --git a/src/bin/pub.ts b/src/bin/pub.ts index 7f1ef22ba..cabe38a08 100755 --- a/src/bin/pub.ts +++ b/src/bin/pub.ts @@ -8,9 +8,9 @@ import help from 'help-me' import minimist, { type ParsedArgs } from 'minimist' import split2 from 'split2' -import { connect } from '../mqtt' import { type IClientOptions, type IClientPublishOptions } from 'src/lib/client' import { pipeline } from 'stream' +import { connect } from '../mqtt' const helpMe = help({ dir: path.join(__dirname, '../../', 'help'), diff --git a/src/bin/sub.ts b/src/bin/sub.ts index 26b3bef7e..a39e283f1 100755 --- a/src/bin/sub.ts +++ b/src/bin/sub.ts @@ -4,8 +4,8 @@ import path from 'path' import fs from 'fs' import minimist from 'minimist' import help from 'help-me' -import { connect } from '../mqtt' import { type IClientOptions } from 'src/lib/client' +import { connect } from '../mqtt' const helpMe = help({ dir: path.join(__dirname, '../../', 'help'), diff --git a/src/lib/client.ts b/src/lib/client.ts index d18a89481..9f693745e 100644 --- a/src/lib/client.ts +++ b/src/lib/client.ts @@ -1,7 +1,6 @@ /** * Module dependencies */ -import TopicAliasRecv from './topic-alias-recv' import mqttPacket, { type IAuthPacket, IConnackPacket, @@ -15,17 +14,18 @@ import mqttPacket, { type ISubackPacket, type IConnectPacket, } from 'mqtt-packet' -import DefaultMessageIdProvider, { - type IMessageIdProvider, -} from './default-message-id-provider' import { type DuplexOptions, Writable } from 'readable-stream' import clone from 'rfdc/default' -import * as validations from './validations' import _debug from 'debug' -import Store, { type IStore } from './store' -import handlePacket from './handlers' import type { ClientOptions } from 'ws' import { type ClientRequestArgs } from 'http' +import * as validations from './validations' +import Store, { type IStore } from './store' +import handlePacket from './handlers' +import DefaultMessageIdProvider, { + type IMessageIdProvider, +} from './default-message-id-provider' +import TopicAliasRecv from './topic-alias-recv' import { type DoneCallback, type ErrorWithReasonCode, diff --git a/src/lib/connect/socks.ts b/src/lib/connect/socks.ts index 7f7c64808..11bda14ce 100644 --- a/src/lib/connect/socks.ts +++ b/src/lib/connect/socks.ts @@ -3,10 +3,10 @@ import { Duplex } from 'stream' import { SocksClient, type SocksProxy } from 'socks' import * as dns from 'dns' import { type SocksProxyType } from 'socks/typings/common/constants' -import { type IStream } from '../shared' import { promisify } from 'util' import { type Socket } from 'net' import assert from 'assert' +import { type IStream } from '../shared' const debug = _debug('mqttjs:socks') diff --git a/src/lib/connect/tcp.ts b/src/lib/connect/tcp.ts index fc702b274..549e37ee0 100644 --- a/src/lib/connect/tcp.ts +++ b/src/lib/connect/tcp.ts @@ -1,7 +1,6 @@ -import { type StreamBuilder } from '../shared' - import net from 'net' import _debug from 'debug' +import { type StreamBuilder } from '../shared' import openSocks from './socks' const debug = _debug('mqttjs:tcp') diff --git a/src/lib/connect/ws.ts b/src/lib/connect/ws.ts index 8e41c44ad..184cd43db 100644 --- a/src/lib/connect/ws.ts +++ b/src/lib/connect/ws.ts @@ -1,8 +1,8 @@ -import { type StreamBuilder } from '../shared' import { Buffer } from 'buffer' import Ws, { type ClientOptions } from 'ws' import _debug from 'debug' import { type DuplexOptions, Transform } from 'readable-stream' +import { type StreamBuilder } from '../shared' import isBrowser from '../is-browser' import { type IClientOptions } from '../client' import type MqttClient from '../client' diff --git a/src/lib/connect/wx.ts b/src/lib/connect/wx.ts index 69a747570..b4b3ec1ed 100644 --- a/src/lib/connect/wx.ts +++ b/src/lib/connect/wx.ts @@ -1,7 +1,6 @@ -import { type StreamBuilder } from '../shared' - import { Buffer } from 'buffer' import { Transform } from 'readable-stream' +import { type StreamBuilder } from '../shared' import { type IClientOptions } from '../client' import type MqttClient from '../client' import { BufferedDuplex } from '../BufferedDuplex' diff --git a/src/lib/get-timer.ts b/src/lib/get-timer.ts index ef0dd30d7..5dc1fb224 100644 --- a/src/lib/get-timer.ts +++ b/src/lib/get-timer.ts @@ -1,5 +1,5 @@ -import isBrowser, { isWebWorker, isReactNativeBrowser } from './is-browser' import { clearInterval as clearI, setInterval as setI } from 'worker-timers' +import isBrowser, { isWebWorker, isReactNativeBrowser } from './is-browser' import type { TimerVariant } from './shared' // dont directly assign globals to class props otherwise this throws in web workers: Uncaught TypeError: Illegal invocation diff --git a/src/lib/handlers/connack.ts b/src/lib/handlers/connack.ts index 91b581c26..4f49e183b 100644 --- a/src/lib/handlers/connack.ts +++ b/src/lib/handlers/connack.ts @@ -1,7 +1,7 @@ +import { type IConnackPacket } from 'mqtt-packet' import { ReasonCodes } from './ack' import TopicAliasSend from '../topic-alias-send' import { ErrorWithReasonCode, type PacketHandler } from '../shared' -import { type IConnackPacket } from 'mqtt-packet' const handleConnack: PacketHandler = (client, packet: IConnackPacket) => { client.log('_handleConnack') diff --git a/test/node/abstract_client.ts b/test/node/abstract_client.ts index cad71e946..7e03cd7aa 100644 --- a/test/node/abstract_client.ts +++ b/test/node/abstract_client.ts @@ -5,6 +5,15 @@ import { assert } from 'chai' import sinon from 'sinon' import fs from 'fs' import levelStore from 'mqtt-level-store' +import { + type IPublishPacket, + type IPubrelPacket, + type ISubackPacket, + type QoS, +} from 'mqtt-packet' +import { type DoneCallback, ErrorWithReasonCode } from 'src/lib/shared' +import { fail } from 'assert' +import { describe, it, beforeEach, afterEach, after } from 'node:test' import Store from '../../src/lib/store' import serverBuilderFn from './server_helpers_for_client_tests' import handlePubrel from '../../src/lib/handlers/pubrel' @@ -18,15 +27,6 @@ import mqtt, { type ISubscriptionMap, type ISubscriptionRequest, } from '../../src' -import { - type IPublishPacket, - type IPubrelPacket, - type ISubackPacket, - type QoS, -} from 'mqtt-packet' -import { type DoneCallback, ErrorWithReasonCode } from 'src/lib/shared' -import { fail } from 'assert' -import { describe, it, beforeEach, afterEach, after } from 'node:test' /** * These tests try to be consistent with names for servers (brokers) and clients, diff --git a/test/node/abstract_store.ts b/test/node/abstract_store.ts index 68df77bbd..fcdfe7b62 100644 --- a/test/node/abstract_store.ts +++ b/test/node/abstract_store.ts @@ -1,7 +1,7 @@ import { type IPublishPacket, type IPubrelPacket } from 'mqtt-packet' -import { type IStore } from '../../src' -import 'should' import { it, beforeEach, afterEach } from 'node:test' +import 'should' +import { type IStore } from '../../src' export default function abstractStoreTest( build: (cb: (err?: Error, store?: IStore) => void) => void, diff --git a/test/node/client.ts b/test/node/client.ts index 0060e4aa2..947c0c75e 100644 --- a/test/node/client.ts +++ b/test/node/client.ts @@ -1,5 +1,4 @@ import { useFakeTimers } from 'sinon' -import mqtt from '../../src' import { assert } from 'chai' import { fork } from 'child_process' import path from 'path' @@ -9,13 +8,14 @@ import mqttPacket from 'mqtt-packet' import { Duplex } from 'readable-stream' import Connection from 'mqtt-connection' import util from 'util' +import _debug from 'debug' +import { type IClientOptions } from 'src/lib/client' +import { describe, it, after } from 'node:test' import getPorts from './helpers/port_list' import serverBuilder from './server_helpers_for_client_tests' -import _debug from 'debug' import { MqttServer } from './server' import abstractClientTests from './abstract_client' -import { type IClientOptions } from 'src/lib/client' -import { describe, it, after } from 'node:test' +import mqtt from '../../src' // eslint-disable-next-line @typescript-eslint/no-var-requires const pkgJson = require('../../package.json') diff --git a/test/node/client_mqtt5.ts b/test/node/client_mqtt5.ts index 708fe9e9e..72f60aa55 100644 --- a/test/node/client_mqtt5.ts +++ b/test/node/client_mqtt5.ts @@ -1,10 +1,10 @@ import { assert } from 'chai' +import { after, describe, it } from 'node:test' import abstractClientTests from './abstract_client' import { MqttServer } from './server' import serverBuilder from './server_helpers_for_client_tests' import getPorts from './helpers/port_list' import mqtt, { type ErrorWithReasonCode } from '../../src' -import { after, describe, it } from 'node:test' const ports = getPorts(1) diff --git a/test/node/keepaliveManager.ts b/test/node/keepaliveManager.ts index 0858731eb..8bbab6ce0 100644 --- a/test/node/keepaliveManager.ts +++ b/test/node/keepaliveManager.ts @@ -1,8 +1,8 @@ import { afterEach, beforeEach, describe, it } from 'node:test' -import KeepaliveManager from '../../src/lib/KeepaliveManager' import { assert } from 'chai' import { useFakeTimers, spy, stub } from 'sinon' import { type MqttClient } from 'src' +import KeepaliveManager from '../../src/lib/KeepaliveManager' function mockedClient(keepalive: number) { return { diff --git a/test/node/message-id-provider.ts b/test/node/message-id-provider.ts index 1f4508e8a..76a37965b 100644 --- a/test/node/message-id-provider.ts +++ b/test/node/message-id-provider.ts @@ -1,6 +1,6 @@ import { assert } from 'chai' -import { DefaultMessageIdProvider, UniqueMessageIdProvider } from '../../src' import { describe, it } from 'node:test' +import { DefaultMessageIdProvider, UniqueMessageIdProvider } from '../../src' describe('message id provider', () => { describe('default', () => { diff --git a/test/node/mqtt.ts b/test/node/mqtt.ts index b16915049..408116a61 100644 --- a/test/node/mqtt.ts +++ b/test/node/mqtt.ts @@ -1,7 +1,7 @@ import fs from 'fs' import path from 'path' -import mqtt, { type IClientOptions } from '../../src' import { describe, it } from 'node:test' +import mqtt, { type IClientOptions } from '../../src' import 'should' describe('mqtt', () => { diff --git a/test/node/mqtt_store.ts b/test/node/mqtt_store.ts index 95ec180c3..5f68d8719 100644 --- a/test/node/mqtt_store.ts +++ b/test/node/mqtt_store.ts @@ -1,5 +1,5 @@ -import { Store } from '../../src' import { describe, it } from 'node:test' +import { Store } from '../../src' import 'should' describe('store in lib/connect/index.js (webpack entry point)', () => { diff --git a/test/node/secure_client.ts b/test/node/secure_client.ts index 1fe1ed900..85b28c57c 100644 --- a/test/node/secure_client.ts +++ b/test/node/secure_client.ts @@ -1,11 +1,11 @@ import path from 'path' import fs from 'fs' +import { assert } from 'chai' +import { describe, it, after } from 'node:test' import mqtt from '../../src' import abstractClientTests from './abstract_client' import { MqttSecureServer, type MqttServerListener } from './server' -import { assert } from 'chai' import 'should' -import { describe, it, after } from 'node:test' import getPorts from './helpers/port_list' const ports = getPorts(5) diff --git a/test/node/server_helpers_for_client_tests.ts b/test/node/server_helpers_for_client_tests.ts index 64fa81947..5be6d101e 100644 --- a/test/node/server_helpers_for_client_tests.ts +++ b/test/node/server_helpers_for_client_tests.ts @@ -1,4 +1,3 @@ -import { MqttServer, MqttSecureServer, type MqttServerListener } from './server' import _debug from 'debug' import path from 'path' @@ -8,6 +7,7 @@ import http from 'http' import WebSocket from 'ws' import MQTTConnection from 'mqtt-connection' import { type Server } from 'net' +import { MqttServer, MqttSecureServer, type MqttServerListener } from './server' const KEY = path.join(__dirname, 'helpers', 'tls-key.pem') const CERT = path.join(__dirname, 'helpers', 'tls-cert.pem') diff --git a/test/node/store.ts b/test/node/store.ts index adbeb0a81..41404f591 100644 --- a/test/node/store.ts +++ b/test/node/store.ts @@ -1,6 +1,6 @@ +import { describe } from 'node:test' import Store from '../../src/lib/store' import abstractTest from './abstract_store' -import { describe } from 'node:test' describe('in-memory store', () => { abstractTest(function test(done) { diff --git a/test/node/unique_message_id_provider_client.ts b/test/node/unique_message_id_provider_client.ts index 8fc593399..14db44def 100644 --- a/test/node/unique_message_id_provider_client.ts +++ b/test/node/unique_message_id_provider_client.ts @@ -1,8 +1,8 @@ +import { describe, after } from 'node:test' import abstractClientTests from './abstract_client' import serverBuilder from './server_helpers_for_client_tests' import { UniqueMessageIdProvider, type IClientOptions } from '../../src' import getPorts from './helpers/port_list' -import { describe, after } from 'node:test' const ports = getPorts(3) diff --git a/test/node/websocket_client.ts b/test/node/websocket_client.ts index f0ba077d9..c38c5dbf0 100644 --- a/test/node/websocket_client.ts +++ b/test/node/websocket_client.ts @@ -2,11 +2,11 @@ import http from 'http' import WebSocket from 'ws' import MQTTConnection from 'mqtt-connection' import assert from 'assert' +import { after, describe, it } from 'node:test' import abstractClientTests from './abstract_client' import getPorts from './helpers/port_list' import { MqttServerNoWait } from './server' import mqtt, { type IClientOptions } from '../../src' -import { after, describe, it } from 'node:test' const ports = getPorts(4) From bfb3df1c63befef0434b0eef79582f88b89c72c6 Mon Sep 17 00:00:00 2001 From: DavideViolante Date: Tue, 8 Jul 2025 13:55:26 +0200 Subject: [PATCH 4/8] chore: remove unused rule --- .eslintrc.js | 1 - 1 file changed, 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index be8a30890..b79dbb70c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,7 +30,6 @@ module.exports = { 'consistent-return': 'off', 'max-classes-per-file': 'off', 'no-plusplus': 'off', - 'guard-for-in': 'off', 'no-bitwise': 'off', 'class-methods-use-this': 'off', 'no-continue': 'off', From 18056d0328d751eec246526bc67222fbac699757 Mon Sep 17 00:00:00 2001 From: DavideViolante Date: Tue, 8 Jul 2025 13:58:46 +0200 Subject: [PATCH 5/8] chore: restore prefer-destructuring rule and run lint-fix --- .eslintrc.js | 1 - src/bin/mqtt.ts | 2 +- src/lib/client.ts | 2 +- src/lib/connect/index.ts | 5 +++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index b79dbb70c..9894e1c22 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -33,7 +33,6 @@ module.exports = { 'no-bitwise': 'off', 'class-methods-use-this': 'off', 'no-continue': 'off', - 'prefer-destructuring': 'off', 'no-use-before-define': 'off', // Typescript rules '@typescript-eslint/interface-name-prefix': 'off', diff --git a/src/bin/mqtt.ts b/src/bin/mqtt.ts index 7f2027a44..74f9f1c13 100755 --- a/src/bin/mqtt.ts +++ b/src/bin/mqtt.ts @@ -13,7 +13,7 @@ import publish from './pub' import subscribe from './sub' // eslint-disable-next-line @typescript-eslint/no-var-requires -const version = require('../../package.json').version +const { version } = require('../../package.json') const helpMe = help({ dir: path.join(__dirname, '../../', 'help'), diff --git a/src/lib/client.ts b/src/lib/client.ts index 9f693745e..6eb6dbcb1 100644 --- a/src/lib/client.ts +++ b/src/lib/client.ts @@ -1157,7 +1157,7 @@ export default class MqttClient extends TypedEventEmitter Date: Tue, 8 Jul 2025 14:01:19 +0200 Subject: [PATCH 6/8] chore: remove unused rules --- .eslintrc.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 9894e1c22..3e0cda0e6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -33,11 +33,7 @@ module.exports = { 'no-bitwise': 'off', 'class-methods-use-this': 'off', 'no-continue': 'off', - 'no-use-before-define': 'off', // Typescript rules - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-unused-vars': [ 'error', From 02790444dd915c225fc2c588fd6658008cdd028c Mon Sep 17 00:00:00 2001 From: DavideViolante Date: Tue, 8 Jul 2025 14:03:27 +0200 Subject: [PATCH 7/8] chore: remove ts test --- .github/workflows/typescript-build-test.yml | 35 --------------------- 1 file changed, 35 deletions(-) delete mode 100644 .github/workflows/typescript-build-test.yml diff --git a/.github/workflows/typescript-build-test.yml b/.github/workflows/typescript-build-test.yml deleted file mode 100644 index 15259589a..000000000 --- a/.github/workflows/typescript-build-test.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: TypeScript Compatibility Test - -on: - pull_request: - branches: [ main ] - push: - branches: [ main ] - -jobs: - typescript-compat: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Build MQTT.js - run: | - npm ci - npm run build - - - name: Create test TypeScript project - run: | - mkdir ts-test - cd ts-test - npm init -y - npm install typescript@5.x - npm install ../ - echo "import * as mqtt from 'mqtt'; const client = mqtt.connect('ws://localhost');" > index.ts - echo '{ "compilerOptions": { "esModuleInterop": true, "strict": true } }' > tsconfig.json - npx tsc -p . From 31bbc022720d80cb64703a339c00eb8eac5dd39a Mon Sep 17 00:00:00 2001 From: DavideViolante Date: Tue, 8 Jul 2025 14:07:41 +0200 Subject: [PATCH 8/8] chore: restore import order for should --- test/node/abstract_store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/node/abstract_store.ts b/test/node/abstract_store.ts index fcdfe7b62..077e9b21e 100644 --- a/test/node/abstract_store.ts +++ b/test/node/abstract_store.ts @@ -1,6 +1,6 @@ import { type IPublishPacket, type IPubrelPacket } from 'mqtt-packet' -import { it, beforeEach, afterEach } from 'node:test' import 'should' +import { it, beforeEach, afterEach } from 'node:test' import { type IStore } from '../../src' export default function abstractStoreTest(