diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6f2e699..e516ed0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,14 +1,3 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: "CodeQL" on: @@ -19,23 +8,18 @@ on: schedule: - cron: "29 19 * * 6" +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: analyze: + # The job name is a status check on main, keep it unchanged. name: Analyze (${{ matrix.language }}) - # Runner size impacts CodeQL analysis time. To learn more, please see: - # - https://gh.io/recommended-hardware-resources-for-running-codeql - # - https://gh.io/supported-runners-and-hardware-resources - # - https://gh.io/using-larger-runners (GitHub.com only) - # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + runs-on: ubuntu-latest permissions: - # required for all workflows security-events: write - - # required to fetch internal or private CodeQL packs packages: read - - # only required for workflows in private repositories actions: read contents: read @@ -45,49 +29,20 @@ jobs: include: - language: javascript-typescript build-mode: none - # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' - # Use `c-cpp` to analyze code written in C, C++ or both - # Use 'java-kotlin' to analyze code written in Java, Kotlin or both - # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both - # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, - # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. - # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how - # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v7 + with: + persist-credentials: false - # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} config-file: ./.github/codeql/codeql-config.yml - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # If the analyze step fails for one of the languages you are analyzing with - # "We were unable to automatically build your code", modify the matrix above - # to set the build mode to "manual" for that language. Then modify this step - # to build your code. - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - if: matrix.build-mode == 'manual' - shell: bash - run: | - echo 'If you are using a "manual" build mode for one or more of the' \ - 'languages you are analyzing, replace this with the commands to build' \ - 'your code, for example:' - echo ' make bootstrap' - echo ' make release' - exit 1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index bcf49f5..f13b81b 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -28,18 +28,18 @@ jobs: name: Draft mailtrap-nodejs Release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 ref: main - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v7 with: node-version-file: .tool-versions - name: Compute next version id: bump - uses: actions/github-script@v7 + uses: actions/github-script@v9 with: script: | const fs = require('fs'); @@ -59,10 +59,12 @@ jobs: core.setOutput('branch', `release-${tag}`); - name: Abort if tag already exists - uses: actions/github-script@v7 + uses: actions/github-script@v9 + env: + TAG: ${{ steps.bump.outputs.tag }} with: script: | - const tag = '${{ steps.bump.outputs.tag }}'; + const tag = process.env.TAG; try { await github.rest.git.getRef({ owner: context.repo.owner, @@ -76,10 +78,12 @@ jobs: - name: Generate release notes, abort if nothing to release id: notes - uses: actions/github-script@v7 + uses: actions/github-script@v9 + env: + TAG: ${{ steps.bump.outputs.tag }} with: script: | - const tag = '${{ steps.bump.outputs.tag }}'; + const tag = process.env.TAG; // Detect the previous release tag so notes only cover PRs since then. const latest = await github.rest.repos.getLatestRelease({ @@ -119,7 +123,7 @@ jobs: - name: Prepend new section to CHANGELOG.md if: steps.notes.outputs.release_notes != '' - uses: actions/github-script@v7 + uses: actions/github-script@v9 env: NEXT: ${{ steps.bump.outputs.next }} RELEASE_NOTES: ${{ steps.notes.outputs.release_notes }} @@ -163,12 +167,13 @@ jobs: - name: Create draft GitHub release if: steps.notes.outputs.release_notes != '' - uses: actions/github-script@v7 + uses: actions/github-script@v9 env: + TAG: ${{ steps.bump.outputs.tag }} RELEASE_NOTES: ${{ steps.notes.outputs.release_notes }} with: script: | - const tag = '${{ steps.bump.outputs.tag }}'; + const tag = process.env.TAG; const { data } = await github.rest.repos.createRelease({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8300389..f261fb3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,15 +5,96 @@ on: branches: [main] pull_request: +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: + # The job name is the required status check on main, keep it unchanged. lint: runs-on: ubuntu-latest + timeout-minutes: 15 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v7 + with: + persist-credentials: false + - uses: actions/setup-node@v7 with: - node-version: 20.20.2 + node-version-file: .tool-versions cache: 'yarn' - run: yarn install --frozen-lockfile - run: yarn lint - run: yarn test + + test: + name: test (Node.js ${{ matrix.node-version }}) + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + node-version: [22, 24, 26] + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + - uses: actions/setup-node@v7 + with: + node-version: ${{ matrix.node-version }} + cache: 'yarn' + # Also builds dist/ through the "prepare" script. + - run: yarn install --frozen-lockfile + - run: yarn test + + # Checks every nodemailer major allowed by peerDependencies, from the sources + # and from a consumer project using the packed build. + nodemailer: + name: nodemailer ${{ matrix.nodemailer }} + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + include: + - nodemailer: 9 + types: '@types/nodemailer@^6' + - nodemailer: 10 + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + - uses: actions/setup-node@v7 + with: + node-version-file: .tool-versions + cache: 'yarn' + - run: yarn install --frozen-lockfile + - run: yarn add --dev "nodemailer@^${{ matrix.nodemailer }}" + - run: yarn tsc -p tsconfig.build.json --noEmit + - run: yarn test + - name: Set up consumer project + run: | + yarn pack --filename "$RUNNER_TEMP/mailtrap.tgz" + mkdir "$RUNNER_TEMP/consumer" + cd "$RUNNER_TEMP/consumer" + echo '{ "private": true }' > package.json + yarn add "$RUNNER_TEMP/mailtrap.tgz" "nodemailer@^${{ matrix.nodemailer }}" ${{ matrix.types }} typescript@^5 @types/node@^22 + cat > index.ts <<'EOF' + import { createTransport } from "nodemailer"; + import { MailtrapClient, MailtrapTransport } from "mailtrap"; + + const client = new MailtrapClient({ token: "token" }); + const transport = createTransport(MailtrapTransport({ token: "token" })); + + transport.sendMail({ from: "a@example.com", to: "b@example.com", subject: "s", text: "t", category: "c" }); + client.send({ from: { email: "a@example.com" }, to: [{ email: "b@example.com" }], subject: "s", text: "t" }); + EOF + cp index.ts index.mts + - name: Type-check a CommonJS consumer without esModuleInterop + working-directory: ${{ runner.temp }}/consumer + run: yarn tsc --noEmit --strict --skipLibCheck --module commonjs --moduleResolution node10 --types node index.ts + - name: Type-check a native ESM consumer + working-directory: ${{ runner.temp }}/consumer + run: yarn tsc --noEmit --strict --skipLibCheck --module nodenext --moduleResolution nodenext --types node index.mts diff --git a/.tool-versions b/.tool-versions index 39847f7..fed849c 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -nodejs 20.20.2 +nodejs 24.21.0 yarn 1.22.17 diff --git a/README.md b/README.md index f831fb9..23c28c0 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ To get the most out of this official Mailtrap.io Node.js SDK: - [Verify your domain](https://mailtrap.io/sending/domains) +- Use Node.js 22 or newer + ## Installation You can install the package via [npm](https://www.npmjs.com/) or [yarn](https://yarnpkg.com/): @@ -198,7 +200,7 @@ mailtrap ## Nodemailer Transport -> NOTE: [Nodemailer](https://www.npmjs.com/package/nodemailer) is needed as a dependency. Versions 9 and 10 are supported (Nodemailer 10 requires Node.js 20 or newer). +> NOTE: [Nodemailer](https://www.npmjs.com/package/nodemailer) is needed as a dependency. Versions 9 and 10 are supported. ```sh npm install nodemailer diff --git a/package.json b/package.json index 8ceace5..1bd27d1 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@babel/preset-typescript": "^7.18.6", "@jest/globals": "^29.3.1", "@types/jest": "^29.5.3", - "@types/node": "^18.15.11", + "@types/node": "^22.20.5", "@types/nodemailer": "^6.4.9", "@types/qs": "^6.15.0", "@typescript-eslint/eslint-plugin": "^5.57.1", @@ -34,7 +34,7 @@ "typescript": "^5.0.3" }, "engines": { - "node": ">=16.20.1", + "node": ">=22", "yarn": ">=1.22.17" }, "files": [ diff --git a/yarn.lock b/yarn.lock index b615ffd..169f490 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1465,10 +1465,12 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.15.tgz#de0e1fbd2b22b962d45971431e2ae696643d3f5d" integrity sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw== -"@types/node@^18.15.11": - version "18.15.11" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f" - integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q== +"@types/node@^22.20.5": + version "22.20.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.20.5.tgz#afa7bde6da81b8b83ea4e2f020487e9b148c11fd" + integrity sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA== + dependencies: + undici-types "~6.21.0" "@types/nodemailer@^6.4.9": version "6.4.9" @@ -4893,6 +4895,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"