Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .eslintignore

This file was deleted.

16 changes: 0 additions & 16 deletions .eslintrc.js

This file was deleted.

64 changes: 46 additions & 18 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,43 @@ on:
branches: [main]

jobs:
lint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Use Node.js 22.x
uses: actions/setup-node@v4
with:
node-version: 22.x
cache: "npm"
- run: npm ci
# Pre-existing lint debt (mostly no-useless-escape in the parser)
# predates this workflow and was never enforced in CI before, so
# this is surfaced but non-blocking for now rather than failing
# every PR on unrelated backlog.
- run: npm run lint
continue-on-error: true
- run: npm run typecheck

test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [14.x, 16.x]
node-version: [22.x, 24.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install Deps
run: |
npm install -g yarn
yarn install
- run: yarn run build
- run: yarn test
cache: "npm"
- run: npm ci
- run: npm run build
- run: npm test
- name: Coveralls
uses: coverallsapp/github-action@master
with:
Expand All @@ -42,28 +59,39 @@ jobs:

strategy:
matrix:
node-version: [14.x, 16.x]
node-version: [22.x, 24.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install Deps
run: |
npm install -g yarn
yarn install
- run: yarn run build
- run: yarn test:e2e
cache: "npm"
- run: npm ci
- run: npm run build
- run: npm run test:e2e
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: e2e-${{ matrix.node-version }}
parallel: true

compliance:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Use Node.js 22.x
uses: actions/setup-node@v4
with:
node-version: 22.x
cache: "npm"
- run: npm ci
- run: npm run test:compliance

finish:
needs: [test, e2e]
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
.eslint*
.git*
.prettier*
eslint.config.js
vitest.config.ts
tsconfig.json
node_modules/*
src/*
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This module does not perform any magic such as auto-decoding of messages/attachm

## Requirements

- [node.js](http://nodejs.org/) -- v10.0.0 or newer
- [node.js](http://nodejs.org/) -- v22.0.0 or newer

- An IMAP server to connect to -- tested with gmail

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Legacy regression scenarios to re-verify once FETCH/IDLE exist

`test/test.js` and `test/test-connection-*.js` were deleted as part of the
yarn→npm / jest→vitest modernization pass (2026-07-12). They were pre-TypeScript
carryovers from the original `node-imap` fork: each spun up a fake `net` server,
drove a `require("../dist").default` `Imap` instance through hand-scripted wire
traffic, and asserted on the parsed result with Node's `assert`.

They were already non-executable against the current `src/` — there is no
default-exported `Imap` class anymore, and FETCH/IDLE aren't implemented yet
(only `capability`/`id`/`noop`/`starttls` are). So deleting them removed zero
current coverage. But the specific wire-level scenarios they encoded are *not*
reproduced anywhere in the modern suite (unit/integration/compliance/e2e),
because there's nothing to test them against today. Capturing them here so
they get re-verified once FETCH and IDLE are (re)built, instead of silently
reintroducing bugs the original tests existed to catch.

## 1. Literal fragmentation / backpressure spillover

Source: `test-connection-fetch-spillover.js` (comment cites GH issues #345,
#379, #392, #411).

- A FETCH literal's bytes arrive fragmented across multiple TCP packets
(staggered `socket.push()` calls), not as one clean write.
- The body is delivered as a stream, and the consuming side's
`stream._read`/`push()` can return `false` (backpressure) mid-literal —
the parser/stream plumbing needs to handle that correctly rather than
drop or duplicate bytes.
- Today's parser stores FETCH body content as a plain string
(`src/parser/structure/fetch/body.section.ts`), with no
`Readable`/`highWaterMark` handling at all. When per-part body streaming
is (re)implemented, this exact fragmented-delivery-with-backpressure
scenario needs a real test — a scripted-server byte-chunking test alone
won't catch it unless it specifically targets a FETCH literal mid-stream.

## 2. FETCH body as a quoted string, not just a literal

Source: `test-connection-fetch-stringbody.js`.

- FETCH body sections can be delivered as an IMAP quoted string (`"..."`)
instead of a `{n}` literal. The old client accepted both forms.
- Every current FETCH fixture (`test/integration/specs/fetch.spec.ts`, and
all compliance specs) exercises the literal form only. The quoted-string
path is untested even at the pure-parser level.

## 3. IDLE ordering races

Source: `test-connection-idle-normal.js`, `test-connection-idle-order.js`.

- Keepalive-triggered auto-IDLE, with a delayed (500ms) `status()` call
correctly interrupting an in-flight IDLE, plus a hard-timeout guard.
- A second race: queuing a command with *zero* delay, racing the
in-flight `+idling` continuation response.
- IDLE isn't implemented yet (`driver.idle()` throws
`NotImplementedError` in the compliance suite). When it is, these two
ordering races need dedicated tests — the compliance suite's own
scripted-server model doesn't currently assert on transcript ordering
precisely enough to catch a regression here by accident.

## Action

When FETCH streaming/backpressure and IDLE are (re)implemented, add
compliance specs or targeted integration tests covering the three scenarios
above before considering that work complete.
26 changes: 26 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const js = require("@eslint/js");
const tseslint = require("typescript-eslint");
const prettier = require("eslint-config-prettier");

module.exports = tseslint.config(
{
ignores: [
"dist/**",
"coverage/**",
"test/compliance/reports/**",
"eslint.config.js",
],
},
js.configs.recommended,
...tseslint.configs.recommended,
{
// Preserve the pre-existing severity for these two rules: they were
// "warn" under the old @typescript-eslint v4 recommended config, and
// v8's recommended config promotes them to "error" by default.
rules: {
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": "warn",
},
},
prettier,
);
Loading
Loading